Commit d47c42ec by sikang

first commit

parents
apply plugin: 'com.android.library'
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 3
versionName "1.10.e"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
repositories {
flatDir {
dirs 'libs'
}
}
}
dependencies {
api fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.12'
api(name: 'libimagecapture-release', ext: 'aar')
api(name: 'libcamera-release', ext: 'aar')
api(name: 'libidcardcaptor-release', ext: 'aar')
api(name: 'liblivenessdetector2-release', ext: 'aar')
api(name: 'liblivenessdetectionview2-release', ext: 'aar')
api(name: 'libcommon-release', ext: 'aar')
api("com.android.support:appcompat-v7:$rootProject.ext.supportLibraryVersion", {
exclude module: 'support-v4'
})
api("com.android.support:percent:$rootProject.ext.supportLibraryVersion", {
exclude module: 'support-v4'
})
}
#Contains API Secret used to validate your application. Commit to internal source control; avoid making secret public.
#Wed Dec 13 23:41:10 CST 2017
apiSecret=dcd5e4334ad91cd9a97d34bee217a6e878ce1b842cf2c1bae1209b8184492edc
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/jxu/Downloads/android-sdk-linux/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 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 *;
#}
-keep class com.oliveapp.camerasdk.** {*;}
-keepattributes InnerClasses
-keep class **.R$* {*;}
\ No newline at end of file
package com.oliveapp.liveness.sample;
import android.app.Application;
import android.test.ApplicationTestCase;
/**
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
*/
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.oliveapp.liveness.sample">
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="22" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application>
<activity android:name=".SampleLaunchActivity"
android:screenOrientation="portrait">
<!--<intent-filter>-->
<!--<action android:name="android.intent.action.MAIN" />-->
<!--<category android:name="android.intent.category.LAUNCHER" />-->
<!--</intent-filter>-->
</activity>
<activity android:name=".register.SampleImageCaptureActivity"
android:screenOrientation="portrait"/>
<activity android:name=".SettingActivity"
android:screenOrientation="portrait"/>
<activity android:name=".register.SampleChooseCameraActivity"
android:screenOrientation="portrait"/>
<activity android:name=".register.SampleCameraResultActivity"
android:screenOrientation="portrait"/>
<activity
android:name="SampleStartActivity"
android:label="@string/oliveapp_app_name"
android:screenOrientation="portrait"
android:configChanges="keyboardHidden|orientation|screenSize"/>
<activity android:name=".liveness.SampleLivenessActivity"
android:screenOrientation="portrait"
android:configChanges="keyboardHidden|orientation|screenSize"/>
<activity
android:name="SampleUnusualResultActivity"
android:screenOrientation="portrait"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".idcard_captor.SampleIdcardCaptorActivity"
android:screenOrientation="portrait" />
<activity
android:name=".idcard_captor.SampleIdcardResult"
android:screenOrientation="portrait" />
<activity android:name="SampleSaaSResultActivity"
android:screenOrientation="portrait"
android:configChanges="keyboardHidden|orientation|screenSize"/>
</application>
</manifest>
\ No newline at end of file
package com.oliveapp.liveness.sample;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.liveness.sample.register.SampleChooseCameraActivity;
public class SampleLaunchActivity extends Activity {
public static final String TAG = SampleLaunchActivity.class.getSimpleName();
private Button mCameraButton;
private Button mLivenessButton;
private Button mSettingButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
// 如果有设置全局包名的需要, 在这里进行设置
// PackageNameManager.setPackageName();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample_launch);
mCameraButton = (Button) findViewById(R.id.startButton);
mLivenessButton = (Button) findViewById(R.id.livenessButton);
mSettingButton = (Button) findViewById(R.id.settingButton);
mCameraButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(myself(), SampleChooseCameraActivity.class);
startActivity(i);
}
});
mLivenessButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(myself(), SampleStartActivity.class);
startActivity(i);
}
});
mSettingButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent i = new Intent(myself(), SettingActivity.class);
startActivity(i);
}
});
requestPermission();
}
private Activity myself() {
return this;
}
//========================================================请求权限===================================================//
private static final int PERMISSION_READ_EXTERNAL_STORAGE = 101;
private static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 102;
private static final int PERMISSION_CAMERA = 103;
private boolean requestPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_WRITE_EXTERNAL_STORAGE);
return false;
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSION_READ_EXTERNAL_STORAGE);
return false;
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSION_CAMERA);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
try {
switch (requestCode) {
case PERMISSION_CAMERA: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
Toast.makeText(this, "没有摄像头权限我什么都做不了哦!", Toast.LENGTH_LONG).show();
}
break;
}
case PERMISSION_READ_EXTERNAL_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
Toast.makeText(this, "请打开存储读写权限,确保APP正常运行", Toast.LENGTH_LONG).show();
}
break;
}
case PERMISSION_WRITE_EXTERNAL_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
Toast.makeText(this, "请打开存储读写权限,确保APP正常运行", Toast.LENGTH_LONG).show();
}
break;
}
}
} catch (Exception e) {
LogUtil.e(TAG, "Failed to request Permission", e);
}
}
}
package com.oliveapp.liveness.sample;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Base64;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.liveness.sample.R;
import com.oliveapp.liveness.sample.SampleLaunchActivity;
import com.oliveapp.liveness.sample.liveness.SampleLivenessActivity;
import com.oliveapp.liveness.sample.utils.SampleScreenDisplayHelper;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.DecimalFormat;
public class SampleSaaSResultActivity extends Activity implements View.OnClickListener {
public static final String TAG = SampleSaaSResultActivity.class.getSimpleName();
private ListView mListview;
private ImageView mImageViewClose;
private ImageView mImageViewOpen;
private Button mFinishBtn;
private Button mRetryBtn;
private Button mReturnBtn;
/**
* 存储传回的分析数据
*/
public static String mResultJsonString;
/**
* mIfPassed : 每一个项目是否通过
* mDetail: 每一个项目得到的具体分数
* ITEMS : 显示的所有项目名称
* IFPASSKEY : 用于从json中获取“是否通过”数据的key
* DETAILKEY : 用于从json获取“具体分数”的key
* mImages : 存储传回的两张照片
* mIsFailed : 存储本次检测是否通过
*/
private static final String[] ITEMS = {"大礼包照片是否同一个人", "是否通过防屏幕拍摄", "是否通过防照片翻拍", "是否通过防眼部遮挡", "是否通过防孔洞面具"};
private String[] DETAILKEY = {"is_anti_screen_check_score", "is_anti_picture_check_score", "is_anti_eye_blockage_check_score", "is_anti_hole_check_score"};
private String[] IFPASSKEY = {"is_same_person", "is_anti_screen_check_passed", "is_anti_picture_check_passed", "is_anti_eye_blockage_check_passed", "is_anti_hole_check_passed"};
private boolean[] mIfPassed = new boolean[IFPASSKEY.length];
private String[] mDetail = new String[DETAILKEY.length];
/**
* 大礼包回传两张照片
*/
private static final int BITMAPCOUNT = 2;
private Bitmap[] mImages = new Bitmap[BITMAPCOUNT];
private boolean mIsFailed = false;
private boolean mParseJsonFailed = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/**
* 先解析json数据,若有一项不通过就表示失败
*/
try {
JSONObject json = new JSONObject(mResultJsonString);
JSONObject queryResult = json.getJSONObject("query_image_package_result");
for (int i = 0; i < IFPASSKEY.length; i++) {
mIfPassed[i] = queryResult.getBoolean(IFPASSKEY[i]);
if (!mIfPassed[i]) {
mIsFailed = true;
}
if (i != DETAILKEY.length) {
mDetail[i] = new DecimalFormat("#.#####").format(queryResult.getDouble(DETAILKEY[i]));
}
}
/**
* 解析返回的照片,并设置界面
*/
JSONArray images = queryResult.getJSONArray("query_image_contents");
if (images.length() >= BITMAPCOUNT) {
String image1Base64 = (String) images.get(0);
byte[] image1 = Base64.decode(image1Base64, Base64.NO_WRAP);
mImages[0] = BitmapFactory.decodeByteArray(image1, 0, image1.length);
String image2Base64 = (String) images.get(1);
byte[] image2 = Base64.decode(image2Base64, Base64.NO_WRAP);
mImages[1] = BitmapFactory.decodeByteArray(image2, 0, image2.length);
}
} catch (JSONException e) {
LogUtil.e(TAG, e.toString());
mParseJsonFailed = true;
} finally {
}
/**
* 设置全屏
*/
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
/**
* 决定显示哪个页面
*/
LogUtil.e(TAG, "setContentView");
setContentView(decideWhichLayout());
LogUtil.e(TAG, "after setContentView");
initViews();
/**
* 数据解析没有异常,就尝试显示数据
*/
if (!mParseJsonFailed) {
/**
* 显示分析数据
*/
OliveappSaasResultAdapter adapter = new OliveappSaasResultAdapter(this);
mListview.setAdapter(adapter);
}
}
//=================================初始化===============================//
public void initViews() {
mListview = (ListView) findViewById(R.id.oliveapp_liveness_saas_list);
mImageViewClose = (ImageView) findViewById(R.id.oliveapp_liveness_result_close);
mImageViewOpen = (ImageView) findViewById(R.id.oliveapp_liveness_result_open);
if (mIsFailed) {
mRetryBtn = (Button) findViewById(R.id.oliveapp_liveness_saas_result_retry);
mReturnBtn = (Button) findViewById(R.id.oliveapp_liveness_saas_result_return);
mRetryBtn.setOnClickListener(this);
mReturnBtn.setOnClickListener(this);
} else {
mFinishBtn = (Button) findViewById(R.id.oliveapp_liveness_saas_result_finish);
mFinishBtn.setOnClickListener(this);
}
mImageViewClose.setImageBitmap(mImages[0]);
mImageViewOpen.setImageBitmap(mImages[1]);
}
//==============================选择布局=====================================//
private int decideWhichLayout() {
int layout = -1;
LogUtil.e(TAG, "choose layout");
switch (SampleScreenDisplayHelper.getFixedOrientation(this)) {
case PORTRAIT:
if (SampleScreenDisplayHelper.ifThisIsPhone(this) && mIsFailed) { //手机竖屏失败页面
layout = R.layout.oliveapp_sample_saas_result_fail_portrait_phone;
LogUtil.e(TAG, "oliveapp_sample_saas_result_fail_portrait_phone");
} else if (mIsFailed){//平板竖屏失败页面
layout = R.layout.oliveapp_sample_saas_result_fail_portrait_tablet;
LogUtil.e(TAG, "oliveapp_sample_saas_result_fail_portrait_tablet");
} else if (SampleScreenDisplayHelper.ifThisIsPhone(this)) {//手机竖屏通过页面
LogUtil.e(TAG, "oliveapp_sample_saas_result_success_portrait_phone");
layout = R.layout.oliveapp_sample_saas_result_success_portrait_phone;
} else {//平板通过竖屏界面
LogUtil.e(TAG, "oliveapp_sample_saas_result_success_portrait_tablet");
layout = R.layout.oliveapp_sample_saas_result_success_portrait_tablet;
}
break;
case LANDSCAPE:
if (SampleScreenDisplayHelper.ifThisIsPhone(this)) {
if (mIsFailed) {
layout = R.layout.oliveapp_sample_saas_result_fail_portrait_phone;
} else {
layout = R.layout.oliveapp_sample_saas_result_success_portrait_phone;
}
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
if (mIsFailed) {//失败横屏
layout = R.layout.oliveapp_sample_saas_result_fail_landscape;
} else {//成功横屏
layout = R.layout.oliveapp_sample_saas_result_success_landscape;
}
}
break;
}
return layout;
}
/**
* 此处界面跳转的时候要考虑到Activity的跳转和后台的回退栈
* 所以有的地方是finish()
* 而有的地方是startActivity()
*/
@Override
public void onClick(View view) {
Intent intent = new Intent();
int i = view.getId();
if (i == R.id.oliveapp_liveness_saas_result_finish) {
intent.setClass(SampleSaaSResultActivity.this, SampleLaunchActivity.class);
} else if (i == R.id.oliveapp_liveness_saas_result_retry) {
finish();
return;
} else if (i == R.id.oliveapp_liveness_saas_result_return) {
intent.setClass(SampleSaaSResultActivity.this, SampleLaunchActivity.class);
}
startActivity(intent);
finish();
}
//===========================================用来显示比对数据的ListView的数据填充===========================================//
class ViewHolder {
TextView item;
TextView detail;
ImageView result;
}
class OliveappSaasResultAdapter extends BaseAdapter {
private Context mContext;
public OliveappSaasResultAdapter(Context context) {
mContext = context;
}
@Override
public int getCount() {
return IFPASSKEY.length;
}
@Override
public Object getItem(int i) {
return i;
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder = null;
if (view == null) {
view = LayoutInflater.from(mContext).inflate(R.layout.oliveapp_sample_saas_result_item, null);
holder = new ViewHolder();
holder.item = (TextView) view.findViewById(R.id.oliveapp_liveness_result_item);
holder.detail = (TextView) view.findViewById(R.id.oliveapp_liveness_result_detail);
holder.result = (ImageView) view.findViewById(R.id.oliveapp_liveness_result_yesorno);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
if (mIfPassed[i]) {
holder.result.setImageResource(R.mipmap.oliveapp_liveness_result_right);
} else {
holder.result.setImageResource(R.mipmap.oliveapp_liveness_result_wrong);
holder.detail.setTextColor(Color.RED);
}
holder.item.setText(ITEMS[i]);
if (i == 0) {
holder.detail.setText("");
} else {
holder.detail.setText(mDetail[i - 1]);
}
view.setLayoutParams(new ListView.LayoutParams(mListview.getWidth(), mListview.getHeight() / getCount()));
holder.item.setTextSize(TypedValue.COMPLEX_UNIT_PX, mListview.getWidth() / 18);
holder.detail.setTextSize(TypedValue.COMPLEX_UNIT_PX, mListview.getWidth() / 27);
return view;
}
}
}
package com.oliveapp.liveness.sample;
import android.Manifest;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.RelativeLayout;
import android.widget.Toast;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.liveness.sample.R;
import com.oliveapp.liveness.sample.liveness.SampleLivenessActivity;
import com.oliveapp.liveness.sample.utils.SampleScreenDisplayHelper;
public class SampleStartActivity extends Activity {
private static final String TAG = SampleStartActivity.class.getSimpleName();
private Button mStartLivenessButton;
private ImageButton mCloseLivenessButton;
private View mAnimCircleView;
private RelativeLayout mAnimLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(decideWhichLayout());
mStartLivenessButton = (Button) findViewById(R.id.oliveappStartLivenessButton);
mCloseLivenessButton = (ImageButton) findViewById(R.id.oliveappCloseLivenessButton);
mStartLivenessButton.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_UP:
//判断手指抬起时,是否还在按钮范围内
float diffX = motionEvent.getRawX() - mStartLivenessButton.getX();
float diffY = motionEvent.getRawY() - mStartLivenessButton.getY();
// if ((diffX >= 0) && (diffX < mStartLivenessButton.getWidth()) && (diffY >= 0) && (diffY < mStartLivenessButton.getHeight())) {
startAnimation(motionEvent.getRawX(), motionEvent.getRawY(), mStartLivenessButton.getHeight() * 0.6f, 300);
enableStartButton(false);
// }
break;
}
return false;
}
});
mCloseLivenessButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
requestPermission();
}
@Override
protected void onResume() {
super.onResume();
//每次进入,先设置button是否可点击
enableStartButton(true);
}
//=======================================================设置控件====================================================//
public void enableStartButton(boolean enable) {
mStartLivenessButton.setEnabled(enable);
}
//========================================================请求权限===================================================//
private static final int PERMISSION_READ_EXTERNAL_STORAGE = 101;
private static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 102;
private static final int PERMISSION_CAMERA = 103;
private boolean requestPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_WRITE_EXTERNAL_STORAGE);
return false;
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSION_READ_EXTERNAL_STORAGE);
return false;
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSION_CAMERA);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
try {
switch (requestCode) {
case PERMISSION_CAMERA: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mStartLivenessButton.callOnClick();
} else {
Toast.makeText(this, "没有摄像头权限我什么都做不了哦!", Toast.LENGTH_LONG).show();
}
break;
}
case PERMISSION_READ_EXTERNAL_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mStartLivenessButton.callOnClick();
} else {
Toast.makeText(this, "请打开存储读写权限,确保APP正常运行", Toast.LENGTH_LONG).show();
}
break;
}
case PERMISSION_WRITE_EXTERNAL_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mStartLivenessButton.callOnClick();
} else {
Toast.makeText(this, "请打开存储读写权限,确保APP正常运行", Toast.LENGTH_LONG).show();
}
break;
}
}
} catch (Exception e) {
LogUtil.e(TAG, "Failed to request Permission", e);
}
}
//==============================================决定采用的布局==============================================//
private int decideWhichLayout() {
int layout = -1;
switch (SampleScreenDisplayHelper.getFixedOrientation(this)) {
case PORTRAIT:
if (SampleScreenDisplayHelper.ifThisIsPhone(this)) {
layout = R.layout.oliveapp_sample_start_portrait_phone;
} else {
layout = R.layout.oliveapp_sample_start_portrait_tablet;
}
break;
case LANDSCAPE:
if (!SampleScreenDisplayHelper.ifThisIsPhone(this)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
layout = R.layout.oliveapp_sample_start_landscape;
} else {
layout = R.layout.oliveapp_sample_start_portrait_phone;
}
break;
}
return layout;
}
//================================================动画相关==============================================//
/**
* 点击“开始检测”按钮的动画调用
*
* @param endX 点击位置的距左边框的距离 单位是像素
* @param endY 点击位置距上边框的距离 单位是像素
* @param radius 需要显示的效果圆型的半径 单位是像素
* @param duration 动画的持续时间,单位毫秒
*/
public void startAnimation(float endX, float endY, float radius, long duration) {
/**
* 1,直接用画圆环的方法
* 2,资源清理
* 3,界面跳转
*/
mAnimLayout = (RelativeLayout) findViewById(R.id.oliveapp_start_button_layout);
mAnimCircleView = new CircleView(this, Color.YELLOW, endX, endY, radius, duration);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
mAnimLayout.addView(mAnimCircleView, lp);
}
/**
* 动画结束之后的界面跳转
*/
public void navToDetection() {
if (requestPermission()) {
Intent i = new Intent(SampleStartActivity.this, SampleLivenessActivity.class);
startActivity(i);
}
}
/**
* 清理动画用到的资源
*/
public void sweepUp() {
if (mAnimCircleView != null) {
mAnimLayout.removeView(mAnimCircleView);
}
}
/**
* 具体负责点击动画的实现
*/
class CircleView extends View {
private Paint mPaint;
private float mRadius;
//圆心坐标
private float x;
private float y;
private long mDuration;
private float currentRadius = Float.MAX_VALUE;
public CircleView(Context context, int color, float cx, float cy, float radius, long duration) {
super(context);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStrokeWidth(2);
mPaint.setColor(color);
x = cx;
y = cy;
mRadius = radius;
mDuration = duration;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (currentRadius == Float.MAX_VALUE) {
startAnimation();
} else {
RectF rect = new RectF();
rect.top = y - (currentRadius + mRadius + 2) / 2;
rect.left = x - (currentRadius + mRadius + 2) / 2;
rect.bottom = y + (currentRadius + mRadius + 2) / 2;
rect.right = x + (currentRadius + mRadius + 2) / 2;
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mRadius - currentRadius);
canvas.drawArc(rect, 0, 360, false, mPaint);
}
}
public void startAnimation() {
ValueAnimator anim = ValueAnimator.ofFloat(0f, mRadius);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
currentRadius = (float) valueAnimator.getAnimatedValue();
invalidate();
}
});
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
sweepUp();
navToDetection();
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
anim.setDuration(mDuration);
anim.start();
}
}
}
package com.oliveapp.liveness.sample;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.liveness.sample.R;
import com.oliveapp.liveness.sample.liveness.SampleLivenessActivity;
import com.oliveapp.liveness.sample.utils.SampleScreenDisplayHelper;
import java.util.HashMap;
import java.util.Map;
public class SampleUnusualResultActivity extends Activity implements View.OnClickListener {
public static final int PARSE_INTENT_FAIL = -1;
public static final int OPERATION_EXCEPTION = 0;
public static final int NETWORK_EXCEPTION = 1;
public static final int TIME_OUT = 2;
public static final int INIT_FAIL = 3;
public static final int PRESTART_FAIL = 4;
public static final int LIVENESS_FAIL = 5;
private final String OPERATION_EXCEPTION_DATA = "操作异常";
private final String NETWORK_EXCEPTION_DATA = "网络异常,请返回重试";
private final String TIME_OUT_DATA = "超时,请返回重试";
private final String INIT_FAIL_DATA = "初始化失败,请检查权限设置和摄像头";
private final String PRESTART_FAIL_DATA = "预检失败, 请检查设置或重试";
private final String LIVENESS_FAIL_DATA = "活检失败,请重试";
private final String PARSE_INTENT_FAIL_DATA = "解析传来的intent失败,请检查";
private Map<Integer, String> mExceptionData;
public static final String keyToGetExtra = "REASON";
public static final String TAG = SampleUnusualResultActivity.class.getSimpleName();
private TextView mOliveappResultTextView;
private Button mOliveappResultReturnBtn;
private Button mOliveappResultRetryBtn;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LogUtil.e(TAG, "[JUMP] enter unusualActivity");
//设置全屏
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
//决定显示哪个页面
setContentView(decideWhichLayout());
init();
//反馈信息
int code = getIntent().getIntExtra(keyToGetExtra, PARSE_INTENT_FAIL);
mOliveappResultTextView.setText(mExceptionData.get(code));
}
//===============================初始化数据=================================//
public void init() {
mExceptionData = new HashMap<>();
mExceptionData.put(PARSE_INTENT_FAIL, PARSE_INTENT_FAIL_DATA);
mExceptionData.put(OPERATION_EXCEPTION, OPERATION_EXCEPTION_DATA);
mExceptionData.put(NETWORK_EXCEPTION, NETWORK_EXCEPTION_DATA);
mExceptionData.put(TIME_OUT, TIME_OUT_DATA);
mExceptionData.put(INIT_FAIL, INIT_FAIL_DATA);
mExceptionData.put(PRESTART_FAIL, PRESTART_FAIL_DATA);
mExceptionData.put(LIVENESS_FAIL, LIVENESS_FAIL_DATA);
mOliveappResultTextView = (TextView) findViewById(R.id.oliveappResultTextView);
mOliveappResultReturnBtn = (Button) findViewById(R.id.oliveapp_liveness_result_return);
mOliveappResultRetryBtn = (Button) findViewById(R.id.oliveapp_liveness_result_retry);
mOliveappResultRetryBtn.setOnClickListener(this);
mOliveappResultReturnBtn.setOnClickListener(this);
}
@Override
public void onClick(View view) {
/**
* 这里如果点击重试按钮,则不用做任何事情,只要finish掉就好了
*/
if (R.id.oliveapp_liveness_result_return == view.getId()) {
Intent intent = new Intent(SampleUnusualResultActivity.this, SampleLaunchActivity.class);
startActivity(intent);
}
finish();
}
//==================================选择布局=====================================//
private int decideWhichLayout() {
int layout = R.layout.oliveapp_sample_result_unusual_portrait_phone;
//选择布局文件
switch (SampleScreenDisplayHelper.getFixedOrientation(this)) {
case PORTRAIT:
if (SampleScreenDisplayHelper.ifThisIsPhone(this)) {
layout = R.layout.oliveapp_sample_result_unusual_portrait_phone;
} else {
layout = R.layout.oliveapp_sample_result_unusual_portrait_tablet;
}
break;
case LANDSCAPE:
if (!SampleScreenDisplayHelper.ifThisIsPhone(this)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
layout = R.layout.oliveapp_sample_result_unusual_landscape;
} else {
layout = R.layout.oliveapp_sample_result_unusual_portrait_phone;
}
break;
}
return layout;
}
}
package com.oliveapp.liveness.sample;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.CheckBoxPreference;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.util.Log;
import android.view.MenuItem;
import com.oliveapp.libcommon.utility.LogUtil;
/**
* Created by lance on 2016/4/13.
*/
public class SettingActivity extends PreferenceActivity implements Preference.OnPreferenceClickListener,Preference.OnPreferenceChangeListener {
public static final String TAG = SettingActivity.class.getSimpleName();
private SharedPreferences mSharedPrefs = null;
private PreferenceScreen mPreferenceScreen;
private CheckBoxPreference mDebugModePreference;
private EditTextPreference mSaaSUrlPreference;
private EditTextPreference mTestIdPreference;
private ListPreference mFanpaiClsImagePreference;
private ListPreference mFanpaiClsThresholdPreference;
private CheckBoxPreference mSaveRgbPreference;
private CheckBoxPreference mSaveOriginImagePreference;
private CheckBoxPreference mSavePackagePreference;
private CheckBoxPreference mSaveFanpaiClsImagePreference;
private CheckBoxPreference mNewPackagePreference; // 新增收图开关配置
private ListPreference mActionCountsListPreference;
private ListPreference mLivenessDetectionOvertimeListPreference;
private ListPreference mActionOneListPreference;
private ListPreference mActionTwoListPreference;
private ListPreference mActionThreeListPreference;
private CheckBoxPreference mFixActionCheckBoxPreference;
private PreferenceCategory mActionSequencePreferenceCategory;
private ListPreference mDarkDetectionListPreference;
private String mActionCountsStr;
private String mActionTimesStr;
private String mFanpaiClsCountStr;
private int mActionCount;
private int mActionTime;
private final int mInf=1000000;
private boolean mFixActionList;
private String[] mActionListArray;
private String mActionOneStr;
private String mActionTwoStr;
private String mActionThreeStr;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_setting);
// getSupportActionBar().setTitle(R.string.titleSetting);
// getSupportActionBar().setDisplayHomeAsUpEnabled(true);
addPreferencesFromResource(R.xml.preferences);
mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
mPreferenceScreen = (PreferenceScreen) findPreference("pref_liveness_dection");
mDebugModePreference = (CheckBoxPreference) findPreference("pref_debug_mode");
mSaaSUrlPreference = (EditTextPreference) findPreference("pref_saas_url");
mTestIdPreference = (EditTextPreference) findPreference("pref_test_id");
mFanpaiClsImagePreference = (ListPreference) findPreference("pref_fanpaicls_counts_list");
mFanpaiClsThresholdPreference = (ListPreference) findPreference("pref_fanpaicls_threshold_list");
mSaveRgbPreference = (CheckBoxPreference) findPreference("pref_save_rgb");
mSaveOriginImagePreference = (CheckBoxPreference) findPreference("pref_save_origin_image");
mSavePackagePreference = (CheckBoxPreference) findPreference("pref_save_package");
mNewPackagePreference = (CheckBoxPreference) findPreference("pref_new_package");
mDarkDetectionListPreference = (ListPreference) findPreference("pref_dark_detect_list");
mActionSequencePreferenceCategory = (PreferenceCategory) findPreference("pref_action_sequence_category");
mLivenessDetectionOvertimeListPreference = (ListPreference)findPreference("pref_liveness_detection_overtime_list");
mActionOneListPreference = (ListPreference)findPreference("pref_action_one_list");
mActionTwoListPreference = (ListPreference)findPreference("pref_action_two_list");
mActionThreeListPreference = (ListPreference)findPreference("pref_action_three_list");
mActionCountsListPreference = (ListPreference)findPreference("pref_action_counts_list");
mActionCountsListPreference.setOnPreferenceChangeListener(this);
mLivenessDetectionOvertimeListPreference.setOnPreferenceChangeListener(this);
mActionOneListPreference.setOnPreferenceChangeListener(this);
mActionTwoListPreference.setOnPreferenceChangeListener(this);
mActionThreeListPreference.setOnPreferenceChangeListener(this);
mDebugModePreference.setOnPreferenceChangeListener(this);
mSaaSUrlPreference.setOnPreferenceChangeListener(this);
mTestIdPreference.setOnPreferenceChangeListener(this);
mFanpaiClsImagePreference.setOnPreferenceChangeListener(this);
mFanpaiClsThresholdPreference.setOnPreferenceChangeListener(this);
mSaveRgbPreference.setOnPreferenceChangeListener(this);
mSaveOriginImagePreference.setOnPreferenceChangeListener(this);
mSavePackagePreference.setOnPreferenceChangeListener(this);
mNewPackagePreference.setOnPreferenceChangeListener(this);
mDarkDetectionListPreference.setOnPreferenceChangeListener(this);
mActionCountsStr = mSharedPrefs.getString("pref_action_counts_list","default");
mActionTimesStr = mSharedPrefs.getString("pref_liveness_detection_overtime_list","default");
mFanpaiClsCountStr = mSharedPrefs.getString("pref_fanpaicls_counts_list","default");
String actionOne = mSharedPrefs.getString("pref_action_one_list","default");
String actionTwo = mSharedPrefs.getString("pref_action_two_list","default");
String actionThree = mSharedPrefs.getString("pref_action_three_list","default");
CharSequence[] entries = mActionOneListPreference.getEntries();
int indexOne = mActionOneListPreference.findIndexOfValue(actionOne);
int indexTwo = mActionTwoListPreference.findIndexOfValue(actionTwo);
int indexThree = mActionThreeListPreference.findIndexOfValue(actionThree);
mActionCountsListPreference.setSummary(mActionCountsStr);
mFanpaiClsImagePreference.setSummary(mFanpaiClsCountStr);
mActionOneListPreference.setSummary(entries[indexOne]);
mActionTwoListPreference.setSummary(entries[indexTwo]);
mActionThreeListPreference.setSummary(entries[indexThree]);
mSaaSUrlPreference.setSummary(mSharedPrefs.getString("pref_saas_url","default"));
mTestIdPreference.setSummary(mSharedPrefs.getString("pref_test_id","default"));
mFanpaiClsThresholdPreference.setSummary(mSharedPrefs.getString("pref_fanpaicls_threshold_list","default"));
mDarkDetectionListPreference.setSummary(mSharedPrefs.getString("pref_dark_detect_list", "无"));
setActionSequenceCounts(mActionCountsStr);
setFanpaiClsCount(mActionCountsStr);
mActionCount= Integer.valueOf(mActionCountsStr);
mFixActionCheckBoxPreference = (CheckBoxPreference)getPreferenceManager().findPreference("pref_fix_action");
mFixActionCheckBoxPreference.setOnPreferenceChangeListener(this);
mFixActionList = mSharedPrefs.getBoolean("pref_fix_action", true);
if(mFixActionList){
mPreferenceScreen.addPreference(mActionSequencePreferenceCategory);
}else{
mPreferenceScreen.removePreference(mActionSequencePreferenceCategory);
}
Log.d(TAG,"this is SettingActivity mActionCount="+mActionCount);
if(mActionTimesStr.equals(String.valueOf(mInf))){
mActionTime = mInf;
mLivenessDetectionOvertimeListPreference.setSummary("永不超时");
}else{
mActionTime = Integer.valueOf(mActionTimesStr);
mLivenessDetectionOvertimeListPreference.setSummary(mActionTime/1000+"秒");
}
Log.d(TAG,"this is SettingActivity mActionTime="+mActionTime);
Log.d(TAG,"this is SettingActivity mInf ="+mInf);
Log.d(TAG,"this is SettingActivity mFixActionList="+mFixActionList);
String[] actionListArray = new String[]{mActionOneStr,mActionTwoStr,mActionThreeStr};
mActionListArray = new String[mActionCount];
for(int i = 0; i < mActionCount; i++){
mActionListArray[i] = actionListArray[i];
}
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
this.finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void setActionSequenceCounts(String s){
if(s.equals("1")) {
mActionSequencePreferenceCategory.removePreference(mActionTwoListPreference);
mActionSequencePreferenceCategory.removePreference(mActionThreeListPreference);
mActionSequencePreferenceCategory.addPreference(mActionOneListPreference);
}else if(s.equals("2")) {
mActionSequencePreferenceCategory.removePreference(mActionThreeListPreference);
mActionSequencePreferenceCategory.addPreference(mActionOneListPreference);
mActionSequencePreferenceCategory.addPreference(mActionTwoListPreference);
}else if(s.equals("3")) {
mActionSequencePreferenceCategory.addPreference(mActionOneListPreference);
mActionSequencePreferenceCategory.addPreference(mActionTwoListPreference);
mActionSequencePreferenceCategory.addPreference(mActionThreeListPreference);
}
}
private void setFanpaiClsCount(String s){
if(s.equals("1")) {
CharSequence[] entries = {"1"};
mFanpaiClsImagePreference.setEntries(entries);
mFanpaiClsImagePreference.setEntryValues(entries);
} else {
CharSequence[] entries = {"1", s};
mFanpaiClsImagePreference.setEntries(entries);
mFanpaiClsImagePreference.setEntryValues(entries);
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
LogUtil.i(TAG, "[onPreferenceChange] newValue: " + newValue);
if(ListPreference.class.isInstance(preference)){
Log.d(TAG, "[onPreferenceChange] preference is ListPreference");
String textValue = newValue.toString();
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(textValue);
CharSequence[] entries = listPreference.getEntries();
CharSequence[] entryValues = listPreference.getEntryValues();
Log.d(TAG, "this is lance tag entries[index]=" + entries[index]);
listPreference.setSummary(listPreference.getEntry() == null ? listPreference.getSummary() : entries[index]);
if(listPreference == mLivenessDetectionOvertimeListPreference) {
String value = String.valueOf(entryValues[index]);
if(value.equals(String.valueOf(mInf))){
mActionTime = mInf;
}
mActionTime = Integer.valueOf(value);
Log.d(TAG,"this is Setting mActionTime="+mActionTime);
} else if(listPreference == mActionCountsListPreference) {
mActionCountsStr = String.valueOf(entries[index]);
mActionCount = Integer.valueOf(mActionCountsStr);
setActionSequenceCounts(String.valueOf(entries[index]));
setFanpaiClsCount(String.valueOf(entries[index]));
//重置成1
SharedPreferences.Editor editor = mSharedPrefs.edit();
editor.putString("pref_fanpaicls_counts_list", "1");
editor.commit();
mFanpaiClsImagePreference.setSummary("1");
} else if(listPreference == mActionOneListPreference){
mActionOneStr = String.valueOf(entries[index]);
}else if(listPreference == mActionTwoListPreference){
mActionTwoStr = String.valueOf(entries[index]);
}else if(listPreference == mActionThreeListPreference){
mActionThreeStr = String.valueOf(entries[index]);
}
} else if(CheckBoxPreference.class.isInstance(preference)){
Log.d(TAG, "[onPreferenceChange] preference is CheckBoxPreference");
boolean myValue = (Boolean) newValue;
if(preference == mFixActionCheckBoxPreference){
mFixActionList = myValue;
Log.d(TAG,"this is Setting mFixActionList="+mFixActionList);
if(myValue){
mPreferenceScreen.addPreference(mActionSequencePreferenceCategory);
}else{
mPreferenceScreen.removePreference(mActionSequencePreferenceCategory);
}
}
LogUtil.i(TAG, "[onPreferenceChanged] writeLivenessRuntimeConfig::Custom mode");
} else if (EditTextPreference.class.isInstance(preference)) {
LogUtil.i(TAG, "[onPreferenceChanged] setSummary");
preference.setSummary(newValue.toString());
}
return true;
}
@Override
public boolean onPreferenceClick(Preference preference) {
return true;
}
}
package com.oliveapp.liveness.sample.idcard_captor;
import android.content.Intent;
import android.os.Bundle;
import com.oliveapp.face.idcardcaptorsdk.captor.CapturedIDCardImage;
import com.oliveapp.liveness.sample.idcard_captor.view_controller.SampleIdcardCaptorMainActivity;
/**
* SampleIdcardCaptorActivity
* 如果不想关心界面实现细节,可以直接在此Activity中实现界面跳转逻辑
*/
public class SampleIdcardCaptorActivity extends SampleIdcardCaptorMainActivity {
@Override
public void onCreate(Bundle savedInstance) {
// 如果有设置全局包名的需要, 在这里进行设置
// PackageNameManager.setPackageName();
super.onCreate(savedInstance);
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onFrameResult(int status) {
super.onFrameResult(status);
}
/**
* 捕获到最好的一张身份证照片
*/
@Override
public void onIDCardCaptured(CapturedIDCardImage data) {
super.onIDCardCaptured(data);
// 处理Activity跳转逻辑
Intent i = new Intent(SampleIdcardCaptorActivity.this, SampleIdcardResult.class);
i.putExtra("image", data.idcardImageData);
startActivity(i);
finish();
}
}
package com.oliveapp.liveness.sample.idcard_captor;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;
import com.oliveapp.liveness.sample.R;
public class SampleIdcardResult extends Activity {
public static final String TAG = SampleIdcardResult.class.getSimpleName();
private ImageView mOliveappLivenessImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.oliveapp_activity_sample_idcard_result);
mOliveappLivenessImageView = (ImageView) findViewById(R.id.oliveappLivenessImageView);
byte[] imageContent = getIntent().getByteArrayExtra("image");
Bitmap image = BitmapFactory.decodeByteArray(imageContent, 0, imageContent.length);
mOliveappLivenessImageView.setImageBitmap(image);
}
}
package com.oliveapp.liveness.sample.idcard_captor.view_controller;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.oliveapp.camerasdk.CameraManager;
import com.oliveapp.camerasdk.PhotoModule;
import com.oliveapp.camerasdk.utils.CameraUtil;
import com.oliveapp.face.idcardcaptorsdk.captor.CapturedIDCardImage;
import com.oliveapp.face.idcardcaptorsdk.captor.IDCardCaptor;
import com.oliveapp.face.idcardcaptorsdk.captor.IDCardCaptureEventHandlerIf;
import com.oliveapp.face.idcardcaptorsdk.captor.datatype.FrameData;
import com.oliveapp.face.idcardcaptorsdk.captor.datatype.IDCardStatus;
import com.oliveapp.face.idcardcaptorsdk.nativecode.session_manager.ImageForVerifyConf;
import com.oliveapp.libcommon.uicomponents.VerticalTextView;
import com.oliveapp.libcommon.utility.ApplicationParameters;
import com.oliveapp.libcommon.utility.ImageUtil;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.libcommon.utility.PackageNameManager;
import com.oliveapp.liveness.sample.R;
import junit.framework.Assert;
import java.io.ByteArrayOutputStream;
import java.util.Timer;
import java.util.TimerTask;
import static com.oliveapp.face.idcardcaptorsdk.captor.IDCardCaptor.CARD_TYPE_FRONT;
public class SampleIdcardCaptorMainActivity extends Activity implements CameraManager.CameraPreviewDataCallback, IDCardCaptureEventHandlerIf, CameraManager.CameraPictureCallback {
public static final String TAG = SampleIdcardCaptorMainActivity.class.getSimpleName();
public static final int REQUEST_CODE = 10001;
// Camera Preview Parameter
private static final float TARGET_PREVIEW_RATIO = 16 / 9f; // 摄像头Previwe预览界面的长宽比 默认使用16:9(因为要铺满全屏)
private static final int MAX_PREVIEW_WIDTH = 1920; // 摄像头Preview预览界面的最大宽度,默认使用分辨率1920x1080
private String mPackageName; // 包名
private PhotoModule mPhotoModule; // 摄像头模块
private IDCardCaptor mCaptor; // IDCARD CAPTOR
private VerticalTextView mVerticalTextView;
private ImageButton mTakePictureButton;
private ImageView mIdcardShadeView;
private View mPreview;
private ImageView mScanLineImageView;
private int mIdcardLeft;
private int mIdcardRight;
private int mIdcardTop;
private int mIdcardBottom;
// 真正发生preview的surface或者texture的位置
private int mPreviewLeft;
private int mPreviewRight;
private int mPreviewTop;
private int mPreviewBottom;
private int mPreviewFrameWidth;
private int mPreviewFrameHeight;
// 捕获模式
public static final int CAPTURE_MODE_AUTO = 0x00; // 自动捕获
public static final int CAPTURE_MODE_MANUAL = 0x01; // 手动拍摄
public static final int CAPTURE_MODE_MIXED = 0x10; // 混合模式,首先尝试自动捕获,指定时间后,采取手动拍摄
public int mCaptureMode; // 捕获模式
public int mCardType; // 身份证类型:正面/反面
public int mDurationTime; // 尝试自动捕获时间,单位为秒,仅混合模式有效
public static final String EXTRA_CAPTURE_MODE = "capture_mode";
public static final String EXTRA_CARD_TYPE = "card_type";
public static final String EXTRA_DURATION_TIME = "duration_time";
// 定时器与定时任务,用于混合模式
private Timer mTimer;
private TimerTask mTimerTask;
// 是否处于自动模式/混合模式
private Boolean bIsAuto = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
LogUtil.e(TAG, "Uncaught exception", ex);
}
});
if (!PackageNameManager.isPackageNameSet()) {
PackageNameManager.setPackageName(getPackageName());
}
PackageNameManager.setPackageName(PackageNameManager.getPackageName());
super.onCreate(savedInstanceState);
// DEBUG相关: 可以检测Activity内存泄漏
increaseClassObjectCount();
mPackageName = PackageNameManager.getPackageName();
initData();
// 初始化界面元素
initViews();
// 初始化摄像头
initCamera();
// 如果是自动模式/混合模式,初始化身份证捕获模块,
if(bIsAuto) {
initCaptor();
// 如果是混合模式,启动定时任务
if(mCaptureMode == CAPTURE_MODE_MIXED) {
mTimer = new Timer();
mTimerTask = new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
// 计时器停止后,析构捕获模块,同时更新界面
synchronized (bIsAuto) {
bIsAuto = false;
mTakePictureButton.setVisibility(View.VISIBLE);
mVerticalTextView.setVisibility(View.INVISIBLE);
mScanLineImageView.setAnimation(null);
mScanLineImageView.setVisibility(View.INVISIBLE);
if (mCaptor != null) {
mCaptor.uninit();
mCaptor = null;
}
}
}
});
}
};
mTimer.schedule(mTimerTask, mDurationTime * 1000);
}
} else {
mTakePictureButton.setVisibility(View.VISIBLE);
mVerticalTextView.setVisibility(View.INVISIBLE);
mScanLineImageView.setVisibility(View.INVISIBLE);
}
}
@Override
public void onResume() {
Log.i(TAG, "[BEGIN] SampleIdcardCaptorMainActivity::onResume()");
super.onResume();
// 恢复摄像头预览和摄像头实时处理回调
if (mPhotoModule != null) {
mPhotoModule.onResume();
try {
mPhotoModule.setPreviewDataCallback(this, mCameraHandler);
} catch (NullPointerException e) {
LogUtil.e(TAG, "PhotoModule set callback failed", e);
}
}
Log.i(TAG, "[END] SampleIdcardCaptorMainActivity::onResume()");
}
@Override
protected void onPause() {
Log.i(TAG, "[BEGIN] SampleIdcardCaptorMainActivity::onPause()");
super.onPause();
// 暂停摄像头预览
if (mPhotoModule != null) {
mPhotoModule.onPause();
}
Log.i(TAG, "[END] SampleIdcardCaptorMainActivity::onPause()");
}
@Override
protected void onDestroy() {
Log.i(TAG, "[BEGIN] SampleIdcardCaptorMainActivity::onDestroy()");
super.onDestroy();
// 关闭摄像头
if (mPhotoModule != null) {
mPhotoModule.onStop();
}
CameraUtil.sContext = null; // 避免出现引用环造成内存泄漏
mPhotoModule = null;
// 析构捕获模块
if (mCaptor != null) {
mCaptor.uninit();
mCaptor = null;
}
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
if (mTimerTask != null) {
mTimerTask.cancel();
mTimerTask = null;
}
Log.i(TAG, "[END] SampleIdcardCaptorMainActivity::onDestroy()");
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
if(bIsAuto) {
// 扫描动画效果
ImageView skeletonImageView = (ImageView) findViewById(R.id.oliveapp_face_idcardSkeletonImageView);
int[] location = new int[2];
skeletonImageView.getLocationInWindow(location);
int left = skeletonImageView.getLeft();
int right = skeletonImageView.getRight();
int top = skeletonImageView.getTop();
// 平移位置由skeletonImageView在屏幕上的坐标决定
Animation animation = new TranslateAnimation(left - 20, right - 20, top, top);
animation.setDuration(3000);
animation.setRepeatCount(Animation.INFINITE);
animation.setRepeatMode(Animation.RESTART);
mScanLineImageView.startAnimation(animation);
}
}
private void initData() {
mCaptureMode = getIntent().getIntExtra(EXTRA_CAPTURE_MODE, CAPTURE_MODE_MIXED);
if(mCaptureMode == CAPTURE_MODE_AUTO || mCaptureMode == CAPTURE_MODE_MIXED) {
bIsAuto = true;
} else {
bIsAuto = false;
}
mCardType = getIntent().getIntExtra(EXTRA_CARD_TYPE, CARD_TYPE_FRONT);
// 如果是混合模式,则mDurationTime没有作用
mDurationTime = getIntent().getIntExtra(EXTRA_DURATION_TIME, 10);
}
/**
* 初始化界面元素
*/
private void initViews() {
// Fullscreen looks better
if (Build.VERSION.SDK_INT < 16) {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
} else {
/*View decorView = getWindow().getDecorView();
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);*/
// Style中已经设置了NoActionBar
// ActionBar actionBar = getActionBar();
// actionBar.hide();
}
setContentView(R.layout.oliveapp_activity_sample_idcard_captor);
mVerticalTextView = (VerticalTextView) findViewById(R.id.oliveapp_face_hintTextView);
mTakePictureButton = (ImageButton) findViewById(R.id.oliveapp_face_takePictureButton);
mIdcardShadeView = (ImageView) findViewById(R.id.oliveapp_face_idcardSkeletonImageView);
mPreview = findViewById(R.id.oliveapp_face_cameraPreviewView);
mTakePictureButton.setOnClickListener(mTakePhotoButtonClickListener);
mScanLineImageView = (ImageView) findViewById(R.id.oliveapp_face_scan_line);
// DEBUG: 调试相关
mFrameRateText = (TextView) findViewById(R.id.oliveapp_frame_rate_text);
}
private Handler mCameraHandler; // 摄像头回调所在的消息队列
private HandlerThread mCameraHandlerThread; // 摄像头回调所在的消息队列线程
/**
* 初始化并打开摄像头
*/
private void initCamera() {
LogUtil.i(TAG, "[BEGIN] initCamera");
// 寻找设备上的后置摄像头
int cameraCount = Camera.getNumberOfCameras();
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
int expectCameraFacing = Camera.CameraInfo.CAMERA_FACING_BACK;
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo);
LogUtil.i(TAG, "camera id: " + camIdx + ", facing: " + cameraInfo.facing + ", expect facing: " + expectCameraFacing);
if (cameraInfo.facing == expectCameraFacing) {
getIntent().putExtra(CameraUtil.EXTRAS_CAMERA_FACING, camIdx); // 设置需要打开的摄像头ID
getIntent().putExtra(CameraUtil.MAX_PREVIEW_WIDTH, MAX_PREVIEW_WIDTH); // 设置最大Preview宽度
getIntent().putExtra(CameraUtil.TARGET_PREVIEW_RATIO, TARGET_PREVIEW_RATIO); // 设置Preview长宽比
}
}
mPhotoModule = new PhotoModule();
mPhotoModule.init(this, findViewById(R.id.oliveapp_face_cameraPreviewView)); // 参考layout XML文件里定义的cameraPreviewView对象
mPhotoModule.setPlaneMode(false, false); // 取消拍照和对焦功能
mPhotoModule.setShutterRawDataCallback(this);
// 打开摄像头预览
mPhotoModule.onStart();
// 初始化摄像头处理消息队列
mCameraHandlerThread = new HandlerThread("CameraHandlerThread");
mCameraHandlerThread.start();
mCameraHandler = new Handler(mCameraHandlerThread.getLooper());
LogUtil.i(TAG, "[END] initCamera");
}
/**
* 初始化捕获模块
*/
private void initCaptor() {
mCaptor = new IDCardCaptor();
try {
// 在构造捕获模块时,需要制定身份证正面/反面
// 正面:IDCardCaptor.CARD_TYPE_FRONT
// 反面:IDCardCaptor.CARD_TYPE_BACK
mCaptor.init(this, new Handler(getMainLooper()), this, mCardType);
} catch (Exception e) {
LogUtil.e(TAG, "无法初始化身份证翻拍照捕获模块", e);
}
}
private int mCurrentFrameId; // 当前帧ID
/**
* 摄像头取帧回调函数
*/
@Override
public void onPreviewFrame(byte[] data, CameraManager.CameraProxy camera, int faces) {
if(bIsAuto && mCaptor != null) {
mCurrentFrameId++;
Log.d(TAG, "[BEGIN] onPreviewFrame, frameID: " + mCurrentFrameId);
Camera.Size size = camera.getParameters().getPreviewSize();
prepareImageConfigForVerify(size.width, size.height, 0);
// 不处理摄像头打开的前几帧(一般是10)。这些帧有可能比较黑,影响比对结果
if (mCurrentFrameId < ApplicationParameters.CAMERA_DROP_FIRST_DARK_FRAME) {
LogUtil.i(TAG, "onPreviewFrame, drop frame id: " + mCurrentFrameId);
return;
}
LogUtil.i(TAG, "[BEGIN] onPreviewFrame, frame id: " + mCurrentFrameId);
boolean isFrameHandled = false;
// 当前帧
try {
mCaptor.doDetection(data, size.width, size.height);
} catch (Exception e) {
LogUtil.e(TAG, "doDetection failed with exception", e);
}
LogUtil.i(TAG, "[END] onPreviewFrame, 当前帧处理是否处理成功: " + isFrameHandled);
}
}
/**
* 准备图像变换参数
*/
private void prepareImageConfigForVerify(int width, int height, int preRotateDegree) {
// 如果已经
if (FrameData.sImageConfigForVerify != null)
return;
Display display = getWindowManager().getDefaultDisplay();
Point screenSize = new Point();
display.getSize(screenSize);
ImageView skeleton = (ImageView) findViewById(R.id.oliveapp_face_idcardSkeletonImageView);
int locationOnScreen[] = new int[2]; // 画面中透明的身份证区域在屏幕上的尺寸
skeleton.getLocationOnScreen(locationOnScreen);
int skeletonWidth = skeleton.getMeasuredWidth(); // 屏幕的尺寸
int skeletonHeight = skeleton.getMeasuredHeight();
Log.i(TAG, "location on screen: " + locationOnScreen[0] + "," + locationOnScreen[1] + "; skeleton size: " + skeletonWidth + "," + skeletonHeight + "; screen size: " + screenSize.x + "," + screenSize.y);
// 需要按照身份证提示框的1.2倍长、宽来截取画面
FrameData.sImageConfigForVerify = new ImageForVerifyConf(width, height,
760, 480, 1.0f * skeletonHeight / screenSize.y * 1.2f, (locationOnScreen[0] - skeletonWidth * 0.1f) / screenSize.x, preRotateDegree, 0, false);
}
/**
* 单帧结果回调
*/
@Override
public void onFrameResult(int status) {
// IDCardStatus.getHintFromStatus函数可以把状态码变成对应的提示文字
// 当然,如果需要自定义界面,您也可以修改这个函数
mVerticalTextView.setText(IDCardStatus.getHintFromStatus(status));
}
/**
* 翻拍照捕获结果回调
*/
@Override
public void onIDCardCaptured(CapturedIDCardImage data) {
// data.idcardImageData里保存了身份证翻拍照的JPEG数据
mVerticalTextView.setText(IDCardStatus.getHintFromStatus(IDCardStatus.SUCCESS));
}
/**
*
* 点击拍照按钮事件
*
*/
private View.OnClickListener mTakePhotoButtonClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
// 保存控件位置数据,用于裁剪图片,详情请参照cutIdcardImage方法
LogUtil.i(TAG, "用户按了拍摄按钮");
mIdcardBottom = mIdcardShadeView.getBottom();
mIdcardLeft = mIdcardShadeView.getLeft();
mIdcardRight = mIdcardShadeView.getRight();
mIdcardTop = mIdcardShadeView.getTop();
Point previewSize = mPhotoModule.getPreviewSize();
mPreviewFrameWidth = previewSize.x;
mPreviewFrameHeight = previewSize.y;
int midX = (mPreview.getLeft() + mPreview.getRight())/2;
int midY = (mPreview.getTop() + mPreview.getBottom())/2;
mPreviewLeft = midX - mPreviewFrameWidth/2;
mPreviewRight = midX + mPreviewFrameWidth/2;
mPreviewTop = midY - mPreviewFrameHeight/2;
mPreviewBottom = midX + mPreviewFrameHeight/2;
mPhotoModule.captureWithCallBack(false);
}
};
/////////////////// FOR DEBUG //////////////////////
private TextView mFrameRateText;
private static int classObjectCount = 0;
private void increaseClassObjectCount() {
// DEBUG: 检测是否有Activity泄漏
classObjectCount++;
LogUtil.e(TAG, "SampleIdcardCaptorMainActivity classObjectCount onCreate: " + classObjectCount);
// 预期现象是classObjectCount是<10,如果classObjectCount一直在增长,很可能有内存泄漏
if (classObjectCount == 10) {
System.gc();
}
Assert.assertTrue(classObjectCount < 10); // 超过10个对象肯定是内存泄漏,不如crash掉直接暴露问题
}
@Override
public void finalize() {
try {
super.finalize();
} catch (Throwable e) {
LogUtil.e(TAG, "无法完成finalize...", e);
}
// DEBUG: 检测是否有Activity泄漏。与increaseClassObjectCount对应
classObjectCount--;
LogUtil.e(TAG, "SampleIdcardCaptorMainActivity classObjectCount finalize: " + classObjectCount);
}
// 手动拍摄到照片后的回调函数
@Override
public void onPictureTaken(byte[] data, CameraManager.CameraProxy camera) {
LogUtil.i(TAG, "[BEGIN] onPictureTaken...");
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, options);
LogUtil.i(TAG, "original size " + bitmap.getWidth() + "x" + bitmap.getHeight());
bitmap = cutIdcardImage(bitmap);
// 某些手机设置MAX_PICTURE_SIZE无效
int imageHeight;
int imageWidth;
if (bitmap.getWidth() > ApplicationParameters.ID_CARD_UPLOAD_IMAGE_WIDTH + 5) {
imageHeight = (int) (ApplicationParameters.ID_CARD_UPLOAD_IMAGE_WIDTH / (float) bitmap.getWidth() * bitmap.getHeight());
imageWidth = ApplicationParameters.ID_CARD_UPLOAD_IMAGE_WIDTH;
if (1 == (imageHeight & 1)) {
imageHeight -= 1;
}
if (1 == (imageWidth & 1)) {
imageWidth -= 1;
}
bitmap = Bitmap.createScaledBitmap(bitmap, imageWidth, imageHeight, true);
}
// make sure size of image is even, face detect need that
imageWidth = bitmap.getWidth();
imageHeight = bitmap.getHeight();
if ((imageHeight & 1) == 1) {
imageHeight -= 1;
}
if ((imageWidth & 1) == 1) {
imageWidth -= 1;
}
if (imageHeight != bitmap.getHeight() || imageWidth != bitmap.getWidth()) {
bitmap = ImageUtil.getSubBitmap(bitmap, imageWidth, imageHeight);
LogUtil.d(TAG, "get sub image, width: " + bitmap.getWidth() + " imageHeight: " + bitmap.getHeight());
}
LogUtil.i(TAG, "final image size, width: " + bitmap.getWidth() + " height: " + bitmap.getHeight());
byte[] imageContent = ImageUtil.convertBitmapToJPEGByteArray(bitmap, ApplicationParameters.USER_REGISTRATION_UPLOAD_IMAGE_QUALITY);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
// TODO: 最好能够根据当前图片大小,调整压缩率
if (imageContent.length > 600 * 1024) {
Bitmap croppedBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.getWidth() / 4 , bitmap.getHeight() / 4, false);
croppedBitmap.compress(Bitmap.CompressFormat.JPEG, 25, byteArrayOutputStream);
imageContent = byteArrayOutputStream.toByteArray();
} else if (imageContent.length > 200 * 1024) {
bitmap.compress(Bitmap.CompressFormat.JPEG, 25, byteArrayOutputStream);
imageContent = byteArrayOutputStream.toByteArray();
}
// 调用onIDCardCaptured方法,跳转至结果界面
onIDCardCaptured(new CapturedIDCardImage(imageContent));
LogUtil.d(TAG, "[END] onPictureTaken done");
}
public Bitmap cutIdcardImage(Bitmap originalBitmap) {
// 这个图是横的!
// 非常复杂的裁剪图片逻辑!
// 首先获取真实surfaceHolder 或者 textureHolder的位置(使用mPreview的中点,向上下算,可以超出真实Screen), 然后获取ImageView那个身份证框的位置, 这两个是可除的,
// 都是显示像素作为单位
// 之后按照这个比例切出身份证在jpeg上的子图
// 细节可以参考 PhotoUI 的 setTransformMatrix 函数实现
int imageWidth = originalBitmap.getWidth();
int imageHeight = originalBitmap.getHeight();
int targetX = (int)(imageWidth * ((double)(mIdcardTop - mPreviewTop) / mPreviewFrameHeight));
int targetY = (int)(imageHeight * (((double)(mPreviewRight - mIdcardRight) / mPreviewFrameWidth)));
int targetW = (int)(imageWidth * ((double)(mIdcardBottom - mIdcardTop)) / mPreviewFrameHeight);
int targetH = (int)(imageHeight * ((double)(mIdcardRight - mIdcardLeft)) / mPreviewFrameWidth);
return Bitmap.createBitmap(originalBitmap, targetX, targetY, targetW, targetH);
}
}
package com.oliveapp.liveness.sample.libsaasclient.backend;
import android.annotation.TargetApi;
import android.os.Build;
import com.oliveapp.libcommon.utility.LogUtil;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.util.Locale;
/**
* Created by zmzhang on 10/21/15.
*/
public class HashUtil {
public static class Hex {
private static final char[] toDigit = ("0123456789ABCDEF").toCharArray();
private final static String sHexStr = "0123456789ABCDEF";
public static String encode(byte[] bytes) {
char[] chars = new char[2 * bytes.length];
int j = 0;
for (int i = 0; i < bytes.length; ++i) {
byte bits = bytes[i];
chars[j++] = toDigit[((bits >>> 4) & 0xF)];
chars[j++] = toDigit[(bits & 0xF)];
}
return new String(chars);
}
public static byte[] decode(String hexStr) {
hexStr = hexStr.toString().trim().replace(" ", "").toUpperCase(Locale.US);
char[] hexs = hexStr.toCharArray();
byte[] bytes = new byte[hexStr.length() / 2];
int iTmp = 0x00;;
for (int i = 0; i < bytes.length; i++){
iTmp = sHexStr.indexOf(hexs[2 * i]) << 4;
iTmp |= sHexStr.indexOf(hexs[2 * i + 1]);
bytes[i] = (byte) (iTmp & 0xFF);
}
return bytes;
}
}
public static class MD5 {
private final static String TAG = MD5.class.getSimpleName();
public static class Md5EncodingException extends Exception
{
public Md5EncodingException() {}
public Md5EncodingException(String msg)
{
super(msg);
}
}
/**
* Generate MD5 hash code from a given string
* @param message, message to be encoded
* @return encoded MD5 hash string, 32 bytes in hex code
* @throws Md5EncodingException
*/
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public static String md5(String message) throws Md5EncodingException {
try {
// Generate MD5 hash code (16 bytes)
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(message.getBytes(Charset.forName("UTF-8")));
byte messageDigest[] = digest.digest();
// Encode the 16 bytes hash code to 32 bytes hex code.
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++)
hexString.append(Integer.toHexString((messageDigest[i] & 0xFF) | 0x100).substring(1,3));
return hexString.toString();
} catch (Exception e) {
LogUtil.e(TAG, "md5 encoding: ", e);
throw new Md5EncodingException("Cannot generate MD5 hash string.");
}
}
}
}
package com.oliveapp.liveness.sample.libsaasclient.backend;
import android.os.Build;
import com.oliveapp.libcommon.utility.ApplicationParameters;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.libcommon.utility.Metric;
import com.oliveapp.liveness.sample.libsaasclient.datatype.AccessInfo;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.PublicKey;
import java.util.Iterator;
/**
* Created by jthao on 3/6/15.
*/
public class RequestWithSignatureHelper {
private final static String TAG = RequestWithSignatureHelper.class.getSimpleName();
private final static int MAX_BUFFER_SIZE = 1 * 1024 * 1024;
public final static String sDefaultAlias = "yitutest";
private final static String sPublicKeyContent = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiLegYm89cDdoDPp8SnaRY2CLe\n" +
"pviV9y1ve+zgSOz8j2aE2ous4NuxgF38OqnqCbWTzbf1B9vvWgsFTvS+givHDRbo\n" +
"2fhYkNUu36DS/4ltCkZlgZ00GXWUIks9WA1U7ACqyDvvj5MAigqS6wtONTI3wyqM\n" +
"kW0MzeWP2qc5DQUKxQIDAQAB";
public static JSONObject requestWithSignature(URL url, String method, AccessInfo accessInfo, String deviceId,
String requestMessage, int connectTimeoutMilli, int readTimeoutMilli) throws IOException, JSONException {
LogUtil.d(TAG, "request open connection to URL: " + url.toString());
URLConnection urlConn = url.openConnection();
if (urlConn == null) {
throw new IOException("cannot open url " + url.toString());
}
HttpURLConnection conn = (HttpURLConnection) urlConn;
try {
prepareConn(conn, method, accessInfo, deviceId, requestMessage,
connectTimeoutMilli, readTimeoutMilli);
} catch (Exception e) {
LogUtil.e(TAG, "failed to prepareConn", e);
}
String responseString = doRequest(conn, requestMessage);
return new JSONObject(responseString);
}
public static JSONObject requestWithSignature(URL url, String method, AccessInfo accessInfo, String deviceId,
JSONObject requestParams, int connectTimeoutMilli, int readTimeoutMilli) throws IOException, JSONException {
LogUtil.i(TAG, "url: " + url.toString());
URL finalUrl;
switch (method.toUpperCase()) {
case "GET":
// generate URL parameters
Iterator<String> iter = requestParams.keys();
String query = "";
while (iter.hasNext()) {
String key = iter.next();
if (query.length() != 0)
query += "&";
query += (key + "=" + requestParams.getString(key));
}
finalUrl = new URL(url.toString() + "?" + query);
break;
default:
finalUrl = url;
}
String requestContent;
requestContent = requestParams.toString();
return requestWithSignature(finalUrl, method, accessInfo, deviceId, requestContent, connectTimeoutMilli, readTimeoutMilli);
}
private static void prepareConn(HttpURLConnection conn, String method, AccessInfo accessInfo, String deviceId, String requestContent,
int connectTimeoutMilli, int readTimeoutMilli) throws Exception {
conn.setRequestMethod(method);
LogUtil.d(TAG, "request method: " + conn.getRequestMethod());
conn.setRequestProperty("Accept-Encoding", "");
conn.setDoOutput(true);
conn.setConnectTimeout(connectTimeoutMilli);
conn.setReadTimeout(readTimeoutMilli);
LogUtil.d(TAG, "accessId: " + accessInfo.getAccessId());
conn.setRequestProperty("x-access-id", accessInfo.getAccessId());
conn.setRequestProperty("x-device-id", deviceId);
PublicKey publicKey = SignatureUtil.RSAHelper.loadPublicKey(sPublicKeyContent);
String md5hash = SignatureUtil.generateSignature(publicKey, accessInfo.getAccessKey(), requestContent, "");
conn.setRequestProperty("x-signature", md5hash);
conn.setRequestProperty("x-device-model", Build.MODEL);
conn.setRequestProperty("x-os-version-release", Build.VERSION.RELEASE);
conn.setRequestProperty("x-os-version-sdk", Build.VERSION.SDK_INT + "");
conn.setRequestProperty("x-device-brand", Build.BRAND);
conn.setRequestProperty("x-device-manufacturer", Build.MANUFACTURER);
conn.setUseCaches(false);
}
public static String doRequest(HttpURLConnection conn, String requestContent) throws IOException, JSONException {
if (conn == null) {
throw new IOException("cannot open connection");
}
String responseString;
try {
DataOutputStream outputStream = new DataOutputStream(conn.getOutputStream());
LogUtil.d(TAG, "request content " + requestContent);
byte[] requestPaylod = requestContent.getBytes("UTF8");
outputStream.write(requestPaylod, 0, requestPaylod.length);
outputStream.flush();
outputStream.close();
Metric.addAsDouble(Metric.VERIFY_DEBUG_INFO, "Out traffic", requestPaylod.length);
BufferedReader in = null;
if (conn.getResponseCode() != 200) {
in = new BufferedReader(new InputStreamReader(
conn.getErrorStream()));
LogUtil.d(TAG, "Respond code: " + conn.getResponseCode());
} else {
in = new BufferedReader(new InputStreamReader(
conn.getInputStream()));
LogUtil.d(TAG, "Respond code: 200");
}
StringBuffer responseBuf = new StringBuffer();
String inputLine;
while ((inputLine = in.readLine()) != null) {
responseBuf.append(inputLine);
}
in.close();
Metric.addAsDouble(Metric.VERIFY_DEBUG_INFO, "In traffic", responseBuf.length());
responseString = responseBuf.toString();
LogUtil.d(TAG, "response: " + responseString);
} catch (Exception e) {
LogUtil.e(TAG, "exception: ", e);
responseString = new JSONObject().put("rtn", conn.getResponseCode()).put("message", conn.getResponseMessage()).toString();
LogUtil.e(TAG, "response: " + responseString);
throw e;
}
return responseString;
}
}
package com.oliveapp.liveness.sample.libsaasclient.backend;
import android.annotation.TargetApi;
import android.os.Build;
import android.util.Base64;
import com.oliveapp.libcommon.utility.LogUtil;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
/**
* Created by zmzhang on 10/21/15.
*/
public class SignatureUtil {
private final static String TAG = SignatureUtil.class.getSimpleName();
public static class RSAHelper {
public static class PublicKeyException extends Exception
{
public PublicKeyException() {}
public PublicKeyException(String msg)
{
super(msg);
}
}
/**
* Load public key from string
* @param publicKeyStr public key in string format
* @return PublicKey
* @throws PublicKeyException
*/
@TargetApi(Build.VERSION_CODES.FROYO)
public static PublicKey loadPublicKey(String publicKeyStr) throws PublicKeyException {
try {
byte[] buffer = Base64.decode(publicKeyStr, Base64.DEFAULT);
KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (Exception e) {
LogUtil.e(TAG, "Load public key str", e);
throw new PublicKeyException("Cannot load public key from string");
}
}
/**
* Load public key from InputStream
* @param in InputStream of public key
* @throws PublicKeyException
*/
public static PublicKey loadPublicKey(InputStream in) throws Exception {
try {
return loadPublicKey(readKey(in));
} catch (Exception e) {
LogUtil.e(TAG, "Load public key InputStream", e);
throw new PublicKeyException("Cannot load public key from InputStream");
}
}
/**
* Generate public key in string format from InputStream
* @param in InputStream of public key
* @return string represents the public key
* @throws IOException
*/
private static String readKey(InputStream in) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String readLine = null;
StringBuilder sb = new StringBuilder();
while ((readLine = br.readLine()) != null) {
if (readLine.charAt(0) == '-') {
continue;
} else {
sb.append(readLine);
sb.append('\r');
}
}
return sb.toString();
}
/**
* Encrypt message using public key
* @param message string before encrypt
* @param publicKey PublicKey object
* @return byte[] content of the encrypted message
* @throws PublicKeyException
*/
public static byte[] encrypt(byte[] message, PublicKey publicKey) throws PublicKeyException {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] enBytes = cipher.doFinal(message);
return enBytes;
} catch (Exception e) {
e.printStackTrace();
throw new PublicKeyException("Cannot encrypt message with public key");
}
}
}
public static class AESHelper {
public static String keyPart1 = "YITU.INC";
public static byte[] encrypt(byte[] message) {
try {
SecretKeySpec keySpec = new SecretKeySpec(("CopyRight " + keyPart1 + " 2015!").getBytes(), "AES");
byte[] IV = "1234567890123456".getBytes();
IvParameterSpec IVSpec = new IvParameterSpec(IV);
Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, IVSpec);
byte[] encrypted = cipher.doFinal(message);
return encrypted;
} catch (NoSuchAlgorithmException e) {
LogUtil.e(TAG, "[AES Encrypt] NoSuchAlgorithmException...", e);
} catch (NoSuchPaddingException e) {
LogUtil.e(TAG, "[AES Encrypt] NoSuchPaddingException...", e);
} catch (InvalidAlgorithmParameterException e) {
LogUtil.e(TAG, "[AES Encrypt] InvalidAlgorithmParameterException...", e);
} catch (InvalidKeyException e) {
LogUtil.e(TAG, "[AES Encrypt] InvalidKeyException...", e);
} catch (BadPaddingException e) {
LogUtil.e(TAG, "[AES Encrypt] BadPaddingException...", e);
} catch (IllegalBlockSizeException e) {
LogUtil.e(TAG, "[AES Encrypt] IllegalBlockSizeException...", e);
}
return null;
}
}
/**
* Generate signature
* @param publicKey public key used to encrypt message
* @param accessKey access Key
* @param bodyString http body content in string format
* @param userDefinedContent user defined content, must be fewer than 41 bytes
* @return generated encrypted message
*/
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public static String generateSignature(PublicKey publicKey, String accessKey, String bodyString, String userDefinedContent) throws Exception {
String result = null;
// Generate Unix timestamp
int unixTime = (int) (System.currentTimeMillis() / 1000L);
byte[] unixTimeArray = ByteBuffer.allocate(4).putInt(unixTime).array();
// Generate random number
SecureRandom sr = new SecureRandom();
byte[] rndBytes = new byte[8];
sr.nextBytes(rndBytes);
// Combine signature
byte[] signatureStr = mergeArray(accessKey.getBytes(Charset.forName("UTF-8")),HashUtil.MD5.md5(bodyString).getBytes(Charset.forName("UTF-8")));
signatureStr = mergeArray(signatureStr,unixTimeArray);
signatureStr = mergeArray(signatureStr,rndBytes);
signatureStr = mergeArray(signatureStr,userDefinedContent.getBytes(Charset.forName("UTF-8")));
// Encrypt signature
result = HashUtil.Hex.encode(RSAHelper.encrypt(signatureStr, publicKey));
return result;
}
/**
* Combine two byte arrays
* @param a
* @param b
* @return a + b
*/
public static byte[] mergeArray(byte[] a, byte[] b) {
byte[] c = new byte[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
}
package com.oliveapp.liveness.sample.libsaasclient.client;
import android.util.Base64;
import android.util.Log;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.liveness.sample.libsaasclient.backend.RequestWithSignatureHelper;
import com.oliveapp.liveness.sample.libsaasclient.datatype.UserInfo;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.concurrent.TimeoutException;
/**
* Created by jxu on 1/23/16.
*/
public class SaasClient {
public static final String TAG = SaasClient.class.getSimpleName();
private UserInfo mUserInfo;
public String mBaseURL;
public String mURLUploadUserImage;
public String mURLFacePairVerification;
public String mURLCheckUserDatabaseImageStatus;
public String mURLVerifyPairImages;
public String mURLCheckFanpai;
public String mURLTripleVerification;
public SaasClient(UserInfo userInfo) {
mUserInfo = userInfo;
mBaseURL = "http://staging.yitutech.com";
setupUrls();
}
public SaasClient(UserInfo userInfo, String baseUrl) {
mUserInfo = userInfo;
mBaseURL = baseUrl;
setupUrls();
}
private void setupUrls() {
mURLCheckFanpai = mBaseURL + "/face/basic/check_image_package";
LogUtil.e(TAG, "mURLCheckFanpai: " + mURLCheckFanpai);
}
public ArrayList<String> decodePackage(byte[] queryPackage) throws TimeoutException, IOException {
String base64EncodedPackage= Base64.encodeToString(queryPackage, Base64.NO_WRAP);
return decodePackage(base64EncodedPackage);
}
public ArrayList<String> decodePackage(String queryPackageBase64) throws TimeoutException, IOException {
JSONObject requestParams = new JSONObject();
try {
requestParams.put("query_image_package", queryPackageBase64);
requestParams.put("query_image_package_return_image_list", true);
requestParams.put("user_id", "SaasClientTester");
} catch (JSONException e) {
LogUtil.e(TAG, "JsonException in requestParams makeup in packageVerification", e);
}
JSONObject responseJson = null;
try {
responseJson = RequestWithSignatureHelper.requestWithSignature(
new URL(mURLFacePairVerification), "POST",
mUserInfo.getAccessInfo(),
"", requestParams, 2000, 15000);
} catch (JSONException e) {
LogUtil.e(TAG, e.getMessage(), e);
}
ArrayList<String> result = new ArrayList<>();
int rtn = 0;
try {
rtn = responseJson.getInt("rtn");
if (rtn != 0) {
LogUtil.w(TAG, "Request error: " + responseJson.toString());
} else {
LogUtil.i(TAG, "Response content: " + responseJson.toString());
}
} catch (JSONException e) {
LogUtil.e(TAG, "JsonException in response", e);
}
try {
JSONObject packageResult = responseJson.getJSONObject("query_image_package_result");
if (packageResult != null) {
JSONArray imageContents = packageResult.getJSONArray("query_image_contents");
for (int i = 0; i < imageContents.length(); i++) {
result.add(imageContents.getString(i));
}
}
} catch (JSONException e) {
LogUtil.w(TAG, "JsonException in response");
}
return result;
}
public JSONObject checkImagePackage(byte[] queryPackage, String threshold) throws TimeoutException, IOException {
JSONObject requestParams = new JSONObject();
try {
requestParams.put("query_image_package", Base64.encodeToString(queryPackage, Base64.NO_WRAP));
requestParams.put("query_image_package_check_anti_screen", true);
requestParams.put("query_image_package_check_same_person",true);
requestParams.put("query_image_package_check_anti_picture",true);
requestParams.put("query_image_package_check_anti_eye_blockage",true);
requestParams.put("query_image_package_check_anti_hole",true);
requestParams.put("query_image_package_return_image_list",true);
//翻拍照阈值
if (threshold != null) {
requestParams.put("query_image_package_check_anti_screen_threshold", threshold);
}
} catch (JSONException e) {
LogUtil.e(TAG, "JsonException in requestParams makeup in packageVerification", e);
}
JSONObject responseJson = null;
try {
responseJson = RequestWithSignatureHelper.requestWithSignature(
new URL(mURLCheckFanpai), "POST",
mUserInfo.getAccessInfo(),
"", requestParams, 2000, 15000);
} catch (Exception e) {
LogUtil.e(TAG, e.getMessage(), e);
}
return responseJson;
}
}
package com.oliveapp.liveness.sample.libsaasclient.datatype;
import com.oliveapp.libcommon.utility.LogUtil;
import org.json.JSONException;
import org.json.JSONObject;
/**
* AceessInfo代表调用者的身份
*/
public class AccessInfo {
private final static String TAG = "AccessInfo";
private static AccessInfo instance;
public static AccessInfo getInstance() {
if (instance == null)
instance = new AccessInfo("android_accessinfo_not_set", "empty");
return instance;
}
/**
* Setting accessId & accessKey
* @param accessId
* @param accessKey
*/
public AccessInfo setAccessInfo(String accessId, String accessKey) {
if (accessId == null ||
accessId.isEmpty()) {
throw new IllegalArgumentException("invalid accessId");
}
if (accessKey == null || accessKey.isEmpty()) {
throw new IllegalArgumentException("invalid accessKey");
}
mAccessId = accessId;
mAccessKey = accessKey;
LogUtil.w(TAG, "Setting AccessInfo, AccessId:" + accessId);
return this;
}
/**
* 构造AccessInfo
*
* @param accessId 使用者的 AccessId, 需要向依图申请
* @param accessKey 使用者的 AccessKey, 需要向依图申请
*/
private AccessInfo(String accessId, String accessKey) throws IllegalArgumentException {
if (accessId == null ||
accessId.isEmpty()) {
throw new IllegalArgumentException("invalid accessId");
}
if (accessKey == null || accessKey.isEmpty()) {
throw new IllegalArgumentException("invalid accessKey");
}
this.mAccessId = accessId;
this.mAccessKey = accessKey;
}
public static AccessInfo fromJsonString(String jsonString) throws JSONException {
JSONObject jsonObject = new JSONObject(jsonString);
return new AccessInfo(jsonObject.getString("access_id"), jsonObject.getString("access_key"));
}
@Override
public String toString() {
JSONObject object = new JSONObject();
try {
object.put("access_id", mAccessId);
object.put("access_key", mAccessKey);
} catch (JSONException e) {
LogUtil.e(TAG, "fail to transfer access info to string", e);
}
return object.toString();
}
public String getAccessId() {
return this.mAccessId;
}
public String getAccessKey() {
return this.mAccessKey;
}
private String mAccessId; // 客户标识
private String mAccessKey; // 请求密钥
}
package com.oliveapp.liveness.sample.libsaasclient.datatype;
import com.oliveapp.libcommon.utility.LogUtil;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Created by jqshen on 5/24/15.
*/
public class UserInfo {
/**
* 一个注册用户的信息,包含AccessInfo和用户ID
*/
public static String BUNDLE_KEY = "USER_INFO";
private static final String TAG = UserInfo.class.getSimpleName();
private static final int MAX_USER_ID_LENGTH = 80;
private static final int CITIZEN_ID_LENGTH = 18;
private static final int MAX_USER_NAME_LENGTH = 80;
/**
* 构造函数
* @param userId 最大长度: 128字节,utf-8编码
* @param citizenId 用户身份证号,最长18字节,utf-8编码,如果照片类是金融行业带水印的证件照_小, 金融行业带水印的证件照_中, 公安行业带水印的证件照_小, 公安行业带水印的证件照_中之一,则可传入null
* @param userName 最长128字节,用户姓名,如果照片类是金融行业带水印的证件照_小, 金融行业带水印的证件照_中, 公安行业带水印的证件照_小, 公安行业带水印的证件照_中之一,则可传入null
* @param accessInfo 客户标示,
* @exception IllegalArgumentException 传入的参数不符合要求
*/
public UserInfo(String userId,
String citizenId,
String userName,
AccessInfo accessInfo) throws IllegalArgumentException {
setUserId(userId);
mCitizenId = citizenId; // can be empty
mUserName = userName; // can be empty
mAccessInfo = accessInfo;
}
public UserInfo(String userId, AccessInfo accessInfo) throws IllegalArgumentException {
this(userId, "", "", accessInfo);
}
public AccessInfo getAccessInfo() {
return mAccessInfo;
}
public void setAccessInfo(AccessInfo mAccessInfo) throws IllegalArgumentException {
if (mAccessInfo == null) {
throw new IllegalArgumentException("accessInfo is null");
}
this.mAccessInfo = mAccessInfo;
}
public String getUserName() {
return mUserName;
}
public void setUserName(String userName) throws IllegalArgumentException {
if (userName == null) {
throw new IllegalArgumentException("User name is null");
} else if (userName.length() > MAX_USER_NAME_LENGTH) {
throw new IllegalArgumentException("User name exceed " + MAX_USER_NAME_LENGTH);
} else if (userName.isEmpty()) {
throw new IllegalArgumentException("User name is empty");
}
this.mUserName = userName;
}
public String getCitizenId() {
return mCitizenId;
}
public void setCitizenId(String citizenId) {
if (citizenId.length() != CITIZEN_ID_LENGTH) {
throw new IllegalArgumentException("Citizen id lenth is not " + CITIZEN_ID_LENGTH);
}
mCitizenId = citizenId;
}
public String getUserId() {
return mUserId;
}
public void setUserId(String userId) {
if (userId == null) {
throw new IllegalArgumentException("UserId is null");
} else if (userId.length() > MAX_USER_ID_LENGTH) {
throw new IllegalArgumentException("UserId length exceed " + MAX_USER_ID_LENGTH);
} else if (userId.isEmpty()) {
throw new IllegalArgumentException("UserId is empty");
}
mUserId = userId;
}
public String toString() {
JSONObject obj = new JSONObject();
try {
obj.put("user_name", mUserName);
obj.put("citizen_id", mCitizenId);
obj.put("user_id", mUserId);
obj.put("access_info", mAccessInfo.toString());
} catch (JSONException e) {
LogUtil.e(TAG, "Usre Info to string", e);
}
return obj.toString();
}
private AccessInfo mAccessInfo;
private String mUserName;
private String mCitizenId;
private String mUserId;
static public UserInfo fromString(String userBasicInfoString) {
try {
JSONObject obj = new JSONObject(userBasicInfoString);
String userName = obj.getString("user_name");
String citizenId = obj.getString("citizen_id");
String userId = obj.getString("user_id");
AccessInfo accessInfo = AccessInfo.fromJsonString(obj.getString("access_info"));
UserInfo userInfo = new UserInfo(userId, citizenId, userName, accessInfo);
return userInfo;
} catch (Exception e) {
LogUtil.e(TAG, "USER_INFO from string", e);
return null;
}
}
}
package com.oliveapp.liveness.sample.liveness;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Base64;
import android.widget.Toast;
import com.oliveapp.face.livenessdetectorsdk.livenessdetector.datatype.LivenessDetectionFrames;
import com.oliveapp.face.livenessdetectorsdk.livenessdetector.datatype.OliveappFaceInfo;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.liveness.sample.SampleUnusualResultActivity;
import com.oliveapp.liveness.sample.liveness.view_controller.LivenessDetectionMainActivity;
/**
* 样例活体检测Activity
*/
public class SampleLivenessActivity extends LivenessDetectionMainActivity {
public static final String TAG = SampleLivenessActivity.class.getSimpleName();
private ProgressDialog mProgressDialog;
public static String resultString = null;
private LivenessDetectionFrames livenessDetectionFrames;
@Override
protected void onCreate(Bundle savedInstanceState) {
// 如果有设置全局包名的需要, 在这里进行设置
// PackageNameManager.setPackageName();
super.onCreate(savedInstanceState);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
/**
* =====================启动算法===============
**/
@Override
public void onInitializeSucc() {
super.onInitializeSucc();
super.startVerification();
}
@Override
public void onInitializeFail(Throwable e) {
super.onInitializeFail(e);
LogUtil.e(TAG, "无法初始化活体检测...", e);
Toast.makeText(this, "无法初始化活体检测", Toast.LENGTH_LONG).show();
Intent i = new Intent(SampleLivenessActivity.this, SampleUnusualResultActivity.class);
i.putExtra(SampleUnusualResultActivity.keyToGetExtra, SampleUnusualResultActivity.INIT_FAIL);
startActivity(i);
finish();
}
@Override
protected void onPause() {
super.onPause();
if ((mProgressDialog != null) && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
}
/**===================================活体检测算法的回调==================================**/
/**
* 活体检测成功的回调,同时获取大礼包
* 成功回调的接口在1.7.a_hotfix被拆成了2步,不再使用该接口
*
* @param livenessDetectionFrames 活体检测抓取的图片
* @param faceInfo 捕获到的人脸信息
*/
@Override
public void onLivenessSuccess(final LivenessDetectionFrames livenessDetectionFrames, OliveappFaceInfo faceInfo) {
super.onLivenessSuccess(livenessDetectionFrames, faceInfo);
this.livenessDetectionFrames = livenessDetectionFrames;
CheckImagePackage checkImagePackage = new CheckImagePackage();
checkImagePackage.execute();
}
/*@Override
public void onLivenessSuccess(OliveappFaceInfo oliveappFaceInfo) {
super.onLivenessSuccess(null, oliveappFaceInfo);
CheckImagePackage checkImagePackage = new CheckImagePackage();
checkImagePackage.execute();
}*/
/**
* 活检阶段失败
*/
@Override
public void onLivenessFail(int result, LivenessDetectionFrames livenessDetectionFrames) {
super.onLivenessFail(result, livenessDetectionFrames);
runOnUiThread(new Runnable() {
@Override
public void run() {
// Intent intent = new Intent();
// Bundle bundle = new Bundle();
// bundle.putString("FACE_RESULT", null);
// intent.putExtras(bundle);
setResult(Activity.RESULT_OK);
finish();
}
});
}
/**
* 获取大礼包并访问私有云的样例代码,集成时请不要使用
*/
private class CheckImagePackage extends AsyncTask<Void, Void, String> {
@Override
protected void onPreExecute() {
mProgressDialog = ProgressDialog.show(SampleLivenessActivity.this,
null, "正在比对,请稍等", true, false);
}
@Override
protected String doInBackground(Void... voids) {
// 获取大礼包,耗时操作,不可在UI线程执行
return Base64.encodeToString(livenessDetectionFrames.verificationData, Base64.NO_WRAP);
}
@Override
protected void onPostExecute(final String result) {
if (mProgressDialog != null) {
mProgressDialog.dismiss();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
// Intent intent = new Intent();
// Bundle bundle = new Bundle();
// bundle.putString("FACE_RESULT", result);
// intent.putExtras(bundle);
resultString = result;
setResult(Activity.RESULT_OK);
finish();
}
});
}
}
public static class YituFaceResult{
public String resultString;
public YituFaceResult(String result){
resultString = result;
}
}
}
package com.oliveapp.liveness.sample.liveness.view_controller;
import android.app.Activity;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.graphics.Typeface;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.support.percent.PercentLayoutHelper;
import android.support.percent.PercentRelativeLayout;
import android.util.DisplayMetrics;
import android.util.Pair;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import com.oliveapp.camerasdk.PhotoModule;
import com.oliveapp.camerasdk.utils.CameraUtil;
import com.oliveapp.face.livenessdetectionviewsdk.event_interface.ViewUpdateEventHandlerIf;
import com.oliveapp.face.livenessdetectionviewsdk.verification_controller.VerificationController;
import com.oliveapp.face.livenessdetectionviewsdk.verification_controller
.VerificationControllerFactory;
import com.oliveapp.face.livenessdetectionviewsdk.verification_controller.VerificationControllerIf;
import com.oliveapp.face.livenessdetectorsdk.livenessdetector.datatype.FacialActionType;
import com.oliveapp.face.livenessdetectorsdk.livenessdetector.datatype.ImageProcessParameter;
import com.oliveapp.face.livenessdetectorsdk.livenessdetector.datatype.LivenessDetectionFrames;
import com.oliveapp.face.livenessdetectorsdk.livenessdetector.datatype.LivenessDetectorConfig;
import com.oliveapp.face.livenessdetectorsdk.livenessdetector.datatype.OliveappFaceInfo;
import com.oliveapp.face.livenessdetectorsdk.prestartvalidator.datatype.PrestartDetectionFrame;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.libcommon.utility.PackageNameManager;
import com.oliveapp.liveness.sample.R;
import com.oliveapp.liveness.sample.SampleUnusualResultActivity;
import com.oliveapp.liveness.sample.utils.OliveappAnimationHelper;
import com.oliveapp.liveness.sample.utils.SampleScreenDisplayHelper;
import java.util.ArrayList;
import java.util.Arrays;
import static com.oliveapp.camerasdk.utils.CameraUtil.CAMERA_RATIO_16_9;
import static com.oliveapp.liveness.sample.utils.SampleScreenDisplayHelper.OrientationType
.LANDSCAPE;
import static com.oliveapp.liveness.sample.utils.SampleScreenDisplayHelper.OrientationType.PORTRAIT;
/**
* ViewController 实现了主要的界面逻辑
* 如果需要定义界面,请继承此类编写自己的Activity,并自己实现事件响应函数
* 可参考SampleAPP里的ExampleLivenessActivity
*/
public abstract class LivenessDetectionMainActivity extends Activity implements
ViewUpdateEventHandlerIf {
public static final String TAG = LivenessDetectionMainActivity.class.getSimpleName();
/**
* 以下4个变量定义了界面中人脸框的位置,采用百分比形式,要根据UI和屏幕比例动态调整,可参考下面代码。
* 比如一张宽高为900 * 1600的图片,以下变量定义的位置为
* 左上角(x, y) => (900 * 0.15, 1600 * 0.25) = (135, 400)
* 人脸框的宽和高(width,height) => (900 * 0.7, 1600 * 0.5) = (630,800)
*/
private static float mXPercent = 0.271f;
private static float mYPercent = 0.274f;
private static float mWidthPercent = 0.735f;
private static float mHeightPercent = 0.414f;
private PhotoModule mPhotoModule; // 摄像头模块
// private AudioModule mAudioModule; // 音频播放模块
private TextView mOliveappDetectedDirectText; //头像上方的指示图像“请眨眼”
private ImageButton mCloseImageBtn; //关闭按钮
private ImageView mCapFrame;
private TextView mCountDownTextView;
/**
* 默认无预检动作
* WITHOUT_PRESTART,无预检过程
* WITH_PRESTART,有预检过程 (推荐)
*/
private VerificationControllerFactory.VCType mVerificationControllerType =
VerificationControllerFactory.VCType.WITH_PRESTART;
private OliveappAnimationHelper mAnimController; //控制动画播放
private static Handler mAnimationHanlder = null; //播放动画的Handler
private ArrayList<Pair<Double, Double>> mLocationArray; //五官位置
private int mCurrentActionType;
private boolean mIsPrestart = false;
/**
* ====================================生命周期相关函数====================================
**/
@Override
protected void onCreate(Bundle savedInstanceState) {
LogUtil.i(TAG, "[BEGIN] LivenessDetectionMainActivity::onCreate()");
/**
* 有些插件系统用普通方法获取不到PackageName,此代码用于兼容
*/
if (!PackageNameManager.isPackageNameSet()) {
PackageNameManager.setPackageName(getPackageName());
}
PackageNameManager.setPackageName(PackageNameManager.getPackageName());
increaseClassObjectCount();
super.onCreate(savedInstanceState);
/**
* 以下代码是为了配合设置功能,集成时可以删除
*/
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences
(LivenessDetectionMainActivity.this);
boolean isDebug = sharedPrefs.getBoolean("pref_debug_mode", false);
if (isDebug) {
if (sharedPrefs.getBoolean("pref_with_prestart", false)) {
mVerificationControllerType = VerificationControllerFactory.VCType.WITH_PRESTART;
} else {
mVerificationControllerType = VerificationControllerFactory.VCType.WITHOUT_PRESTART;
}
}
/**
* 以上代码是为了配合设置功能,集成时可以删除
*/
// 初始化界面元素
initViews();
// 初始化摄像头
initCamera();
// 初始化检测逻辑控制器(VerificationController)
initControllers();
/**
* 如果有预检的话播放预检相关动画和音频
*/
if (mVerificationControllerType == VerificationControllerFactory.VCType.WITH_PRESTART) {
mAnimationHanlder.post(mPreHintAnimation);
mIsPrestart = true;
} else {
mIsPrestart = false;
}
LogUtil.i(TAG, "[END] LivenessDetectionMainActivity::onCreate()");
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onResume() {
LogUtil.i(TAG, "[BEGIN] LivenessDetectionMainActivity::onResume()");
super.onResume();
if (mPhotoModule != null) {
mPhotoModule.onResume();
// 设置摄像头回调,自此之后VerificationController.onPreviewFrame函数就会源源不断的收到摄像头的数据
}
try {
mPhotoModule.setPreviewDataCallback(mVerificationController, mCameraHandler);
} catch (NullPointerException e) {
LogUtil.e(TAG, "PhotoModule set callback failed", e);
}
if (mAnimationHanlder != null) {
if (mIsPrestart) {
mAnimationHanlder.post(mPreHintAnimation);
} else {
mAnimationHanlder.post(mActionAnimationTask);
}
}
LogUtil.i(TAG, "[END] LivenessDetectionMainActivity::onResume()");
}
@Override
protected void onPause() {
LogUtil.i(TAG, "[BEGIN] LivenessDetectionMainActivity::onPause()");
super.onPause();
if (mPhotoModule != null) {
mPhotoModule.onPause();
}
if (mAnimationHanlder != null) {
mAnimationHanlder.removeCallbacksAndMessages(null);
}
LogUtil.i(TAG, "[END] LivenessDetectionMainActivity::onPause()");
}
@Override
protected void onStop() {
LogUtil.i(TAG, "[BEGIN] LivenessDetectionMainActivity::onStop()");
super.onStop();
LogUtil.i(TAG, "[END] LivenessDetectionMainActivity::onStop()");
}
@Override
protected void onDestroy() {
LogUtil.i(TAG, "[BEGIN] LivenessDetectionMainActivity::onDestroy()");
super.onDestroy();
// 关闭摄像头
if (mPhotoModule != null)
mPhotoModule.onStop();
CameraUtil.sContext = null;
mPhotoModule = null;
// 关闭音频播放
if (mAnimationHanlder != null) {
mAnimationHanlder.removeCallbacksAndMessages(null);
mAnimationHanlder = null;
}
// if (mAudioModule != null) {
// mAudioModule.release();
// mAudioModule = null;
// }
// 退出摄像头处理线程
if (mCameraHandlerThread != null) {
try {
mCameraHandlerThread.quit();
mCameraHandlerThread.join();
} catch (InterruptedException e) {
LogUtil.e(TAG, "Fail to join CameraHandlerThread", e);
}
}
mCameraHandlerThread = null;
// 销毁检测逻辑控制器
if (mVerificationController != null) {
mVerificationController.uninit();
mVerificationController = null;
}
LogUtil.i(TAG, "[END] LivenessDetectionMainActivity::onDestroy()");
}
/**
* ====================================初始化相关函数====================================
**/
private VerificationControllerIf mVerificationController; // 逻辑控制器
private Handler mCameraHandler; // 摄像头回调所在的消息队列
private HandlerThread mCameraHandlerThread; // 摄像头回调所在的消息队列线程
/**
* 初始化并打开摄像头
*/
private void initCamera() {
LogUtil.i(TAG, "[BEGIN] initCamera");
// 寻找设备上的前置摄像头
int cameraCount = Camera.getNumberOfCameras();
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
int expectCameraFacing = Camera.CameraInfo.CAMERA_FACING_FRONT;
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo);
LogUtil.i(TAG, "camera id: " + camIdx + ", facing: " + cameraInfo.facing + ", expect " +
"facing: " + expectCameraFacing);
if (cameraInfo.facing == expectCameraFacing) {
getIntent().putExtra(CameraUtil.EXTRAS_CAMERA_FACING, camIdx); // 设置需要打开的摄像头ID
getIntent().putExtra(CameraUtil.TARGET_PREVIEW_RATIO, CAMERA_RATIO_16_9); //
// 设置Preview长宽比,默认是16:9
}
}
mPhotoModule = new PhotoModule();
mPhotoModule.init(this, findViewById(R.id.oliveapp_cameraPreviewView)); // 参考layout
// XML文件里定义的cameraPreviewView对象
mPhotoModule.setPlaneMode(false, false); // 取消拍照和对焦功能
// 打开摄像头预览
mPhotoModule.onStart();
// 初始化摄像头处理消息队列
mCameraHandlerThread = new HandlerThread("CameraHandlerThread");
mCameraHandlerThread.start();
mCameraHandler = new Handler(mCameraHandlerThread.getLooper());
LogUtil.i(TAG, "[END] initCamera");
}
/**
* 初始化界面元素
*/
private void initViews() {
//设置全屏
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager
.LayoutParams.FLAG_FULLSCREEN);
setContentView(decideWhichLayout());
//音频和动画的Handler
// mAudioModule = new AudioModule();
mAnimationHanlder = new Handler();
//进入活检页面就开启动画
mAnimController = new OliveappAnimationHelper(this);
// DEBUG: 调试相关
mFrameRateText = (TextView) findViewById(R.id.oliveapp_frame_rate_text);
mOliveappDetectedDirectText = (TextView) findViewById(R.id.oliveapp_detected_hint_text);
mOliveappDetectedDirectText.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
mOliveappDetectedDirectText.getPaint().setFakeBoldText(true);
// 倒计时的TextView
mCountDownTextView = (TextView) findViewById(R.id.oliveapp_count_time_textview);
//设置关闭按钮
mCloseImageBtn = (ImageButton) findViewById(R.id.oliveapp_close_image_button);
mCloseImageBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
/**
* 设置脸部捕捉框的位置,请根据自己的UI进行调整
* 因为手机和平板的屏幕比例不同,并且适配不同比例的背景图也不同导致需要相应的适配
*/
mCapFrame = (ImageView) findViewById(R.id.oliveapp_start_frame);
if (!SampleScreenDisplayHelper.ifThisIsPhone(this)) {
PercentRelativeLayout.LayoutParams layoutParams = new PercentRelativeLayout
.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams
.WRAP_CONTENT);
PercentLayoutHelper.PercentLayoutInfo layoutInfo = layoutParams.getPercentLayoutInfo();
if (SampleScreenDisplayHelper.getFixedOrientation(this) == LANDSCAPE) {
layoutInfo.topMarginPercent = 0.2f;
layoutInfo.heightPercent = 0.6f;
layoutInfo.widthPercent = layoutInfo.heightPercent / (float)
SampleScreenDisplayHelper.getScreenScale(this);
layoutInfo.leftMarginPercent = (1 - layoutInfo.widthPercent) / 2;
} else {
layoutInfo.leftMarginPercent = 0.13f;
layoutInfo.widthPercent = 0.74f;
layoutInfo.heightPercent = layoutInfo.widthPercent / (float)
SampleScreenDisplayHelper.getScreenScale(this);
layoutInfo.topMarginPercent = (1 - layoutInfo.heightPercent) / 2 - 0.022f;
}
mCapFrame.setLayoutParams(layoutParams);
}
/**
* UI相关
* 提示文字的布局要动态调整
* 只有平板竖屏的时候要调整
*/
if ((SampleScreenDisplayHelper.getFixedOrientation(this) == PORTRAIT) &&
(!SampleScreenDisplayHelper.ifThisIsPhone(this))) {
PercentRelativeLayout hintLayout = (PercentRelativeLayout) findViewById(R.id
.oliveapp_detected_hint_text_layout);
PercentRelativeLayout.LayoutParams params = new PercentRelativeLayout.LayoutParams(0,
0);
PercentLayoutHelper.PercentLayoutInfo info = params.getPercentLayoutInfo();
info.widthPercent = 1f;
info.heightPercent = 0.052f;
info.topMarginPercent = mYPercent - info.heightPercent;
info.leftMarginPercent = 0;
hintLayout.setLayoutParams(params);
}
}
/**
* 重启活体检测,可以多次调用
*/
private void restartDetection() {
// 隐藏动画界面上的眼睛/下巴/嘴
mCurrentActionType = FacialActionType.UNKNOWN;
mAnimController.playActionAnimation(mCurrentActionType, mLocationArray);
// 释放音频动画资源
releaseAudioAnimination();
// 清空倒计时
mCountDownTextView.setText("");
// 人脸框上方黄色提示语隐藏
mOliveappDetectedDirectText.setText(getString(R.string.oliveapp_step_hint_focus));
// 注销
mVerificationController.uninit();
// 重新初始化音频动画
// mAudioModule = new AudioModule();
mAnimationHanlder = new Handler();
// 初始化
initControllers();
// 是否需要预检
if (mVerificationControllerType == VerificationControllerFactory.VCType.WITH_PRESTART) {
mAnimationHanlder.post(mPreHintAnimation);
mIsPrestart = true;
}
// 预检callback
try {
mPhotoModule.setPreviewDataCallback(mVerificationController, mCameraHandler);
} catch (NullPointerException e) {
LogUtil.e(TAG, "PhotoModule set callback failed", e);
}
// 播放预检动画
if (mAnimationHanlder != null) {
if (mIsPrestart) {
mAnimationHanlder.post(mPreHintAnimation);
} else {
mAnimationHanlder.post(mActionAnimationTask);
}
}
}
// 图片预处理参数
private ImageProcessParameter mImageProcessParameter;
// 活体检测参数
private LivenessDetectorConfig mLivenessDetectorConfig;
/**
* 设置图片处理参数和活体检测参数
*/
private void setDetectionParameter() throws Exception {
/**
* 注意: 默认参数适合手机,一般情况下不需要修改这些参数。如需修改请联系依图工程师
*
* 设置从preview图片中截取人脸框的位置,调用doDetection前必须调用本函数。
* @param shouldFlip 是否左右翻转。一般前置摄像头为false
* @param cropWidthPercent 截取的人脸框宽度占帧宽度的比例
* @param verticalOffsetPercent 截取的人脸框上边缘到帧上边缘的距离占帧高度的比例
* @param preRotationDegree 逆时针旋转角度,只允许0 90 180 270,大部分手机应当是90
*/
mImageProcessParameter = new ImageProcessParameter(false, 1.0f, 0.0f, 90);
// 使用预设配置: 满足绝大多数常见场景
mLivenessDetectorConfig = new LivenessDetectorConfig();
mLivenessDetectorConfig.usePredefinedConfig(0);
/**
* 注意,以下代码是配合SampleApp的设置工程,请在集成时请删除
*/
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
boolean isDebug = sharedPrefs.getBoolean("pref_debug_mode", false);
if (isDebug) {
int actionOne = Integer.valueOf(sharedPrefs.getString("pref_action_one_list", "3"));
int actionTwo = Integer.valueOf(sharedPrefs.getString("pref_action_two_list", "3"));
int actionThree = Integer.valueOf(sharedPrefs.getString("pref_action_three_list", "3"));
mLivenessDetectorConfig.totalActions = Integer.valueOf(sharedPrefs.getString
("pref_action_counts_list", "3"));
mLivenessDetectorConfig.timeoutMs = Integer.valueOf(sharedPrefs.getString
("pref_liveness_detection_overtime_list", "10000"));
mLivenessDetectorConfig.fanapaiClsImageNumber = Integer.valueOf(sharedPrefs.getString
("pref_fanpaicls_counts_list", "10000"));
mLivenessDetectorConfig.fixedActions = sharedPrefs.getBoolean("pref_fix_action", false);
mLivenessDetectorConfig.fixedActionList = Arrays.asList(actionOne, actionTwo,
actionThree);
LogUtil.e(TAG, mLivenessDetectorConfig.fixedActionList.toString());
mLivenessDetectorConfig.saveRgb = sharedPrefs.getBoolean("pref_save_rgb", false);
mLivenessDetectorConfig.saveOriginImage = sharedPrefs.getBoolean
("pref_save_origin_image", false);
mLivenessDetectorConfig.savePackage = sharedPrefs.getBoolean("pref_save_package",
false);
mLivenessDetectorConfig.saveJPEG = sharedPrefs.getBoolean("pref_jpeg_image", false);
mLivenessDetectorConfig.saveFanpaiCls = sharedPrefs.getBoolean
("pref_fanpaicls_image", false);
// mLivenessDetectorConfig.newPackage = sharedPrefs.getBoolean("pref_new_package", true);
//此处默认值为0, 代表无昏暗检测
// mLivenessDetectorConfig.darkLevel = getDarkLevelFromDesc(sharedPrefs.getString
// ("pref_dark_detect_list", "0"));
}
/** 注意,以上代码集成时请删除 **/
if (mLivenessDetectorConfig != null) {
mLivenessDetectorConfig.validate();
}
//如果超时时间太长的话便不显示倒计时
if (mLivenessDetectorConfig.timeoutMs >= 1000000) {
mCountDownTextView.setVisibility(View.INVISIBLE);
}
}
/**
* 初始化检测逻辑控制器
* 请先调用setDetectionParameter()设置参数
*/
private void initControllers() {
try {
setDetectionParameter();
} catch (Exception e) {
LogUtil.e(TAG, "初始化参数失败", e);
}
//初始化算法模块
mVerificationController = VerificationControllerFactory.createVerificationController
(mVerificationControllerType, LivenessDetectionMainActivity.this,
mImageProcessParameter,
mLivenessDetectorConfig,
LivenessDetectionMainActivity.this,
new Handler(Looper.getMainLooper()));
//设置人脸框位置
mVerificationController.SetFaceLocation(mXPercent, mYPercent, mWidthPercent,
mHeightPercent);
}
/**===========================算法相关函数==============================**/
/**
* 调用此函数后活体检测即开始
*/
public void startVerification() {
try {
if (mVerificationController.getCurrentStep() == VerificationController.STEP_READY) {
mVerificationController.nextVerificationStep();
}
} catch (Exception e) {
LogUtil.e(TAG, "无法开始活体检测...", e);
}
}
/** ============================== 算法相关的回调函数 ============================**/
/**
* 预检阶段成功
* 请在里面调用mVerificationController.enterLivenessDetection()进入活体检测阶段
*/
@Override
public void onPrestartSuccess(LivenessDetectionFrames livenessDetectionFrames,
OliveappFaceInfo faceInfo) {
LogUtil.i(TAG, "[BEGIN] onPrestartSuccess");
mAnimationHanlder.removeCallbacks(mPreHintAnimation);
mIsPrestart = false;
/**
* 调用此函数进入活体检测过程
*/
mVerificationController.enterLivenessDetection();
LogUtil.i(TAG, "[END] onPrestartSuccess");
}
/**
* 预检阶段每一帧的回调函数
*
* @param frame 每一帧
* @param remainingTimeMillisecond 剩余时间
* @param faceInfo 人脸信息
* @param errorCodeOfInAction 动作不过关的可能原因,可以用来做提示语
*/
@Override
public void onPrestartFrameDetected(PrestartDetectionFrame frame, int
remainingTimeMillisecond, OliveappFaceInfo faceInfo, ArrayList<Integer>
errorCodeOfInAction) {
mFrameRate += 1;
long currentTimestamp = System.currentTimeMillis();
if ((currentTimestamp - mLastTimestamp) > 1000) {
mLastTimestamp = currentTimestamp;
mFrameRateText.setText("FrameRate: " + mFrameRate + " FPS");
mFrameRate = 0;
}
}
/**
* 预检阶段失败,不可能进入此回调
*/
@Override
public void onPrestartFail(int result) {
LogUtil.wtf(TAG, "[END] onPrestartFail");
Intent intent = new Intent(LivenessDetectionMainActivity.this,
SampleUnusualResultActivity.class);
intent.putExtra(SampleUnusualResultActivity.keyToGetExtra, SampleUnusualResultActivity
.PRESTART_FAIL);
startActivity(intent);
}
/**
* 活体检测成功的回调
*
* @param livenessDetectionFrames 活体检测抓取的图片
* @param faceInfo 捕获到的人脸信息
*/
@Override
public void onLivenessSuccess(LivenessDetectionFrames livenessDetectionFrames,
OliveappFaceInfo faceInfo) {
releaseAudioAnimination();
}
// 关闭音频&动画
private void releaseAudioAnimination() {
if (mAnimationHanlder != null) {
mAnimationHanlder.removeCallbacksAndMessages(null);
mAnimationHanlder = null;
}
// if (mAudioModule != null) {
// mAudioModule.release();
// mAudioModule = null;
// }
}
/**
* 活检阶段失败
*/
@Override
public void onLivenessFail(int result, LivenessDetectionFrames livenessDetectionFrames) {
}
/**
* 每一帧结果的回调方法
*
* @param currentActionType 当前是什么动作
* @param actionState 当前动作的检测结果
* @param sessionState 整个Session是否通过
* @param remainingTimeoutMilliSecond 剩余时间,以毫秒为单位
* @param faceInfo 检测到的人脸信息,可以用来做动画
* @param errorCodeOfInAction 动作不过关的可能原因,可以用来做提示语
*/
@Override
public void onFrameDetected(int currentActionType, int actionState, int sessionState, int
remainingTimeoutMilliSecond, OliveappFaceInfo faceInfo, ArrayList<Integer>
errorCodeOfInAction) {
LogUtil.i(TAG, "[BEGIN] onFrameDetected " + remainingTimeoutMilliSecond);
mCountDownTextView.setText("" + (remainingTimeoutMilliSecond / 1000 + 1));
mLocationArray = getFaceInfoLocation(mCurrentActionType, faceInfo);
mFrameRate += 1;
long currentTimestamp = System.currentTimeMillis();
if ((currentTimestamp - mLastTimestamp) > 1000) {
mLastTimestamp = currentTimestamp;
mFrameRateText.setText("FrameRate: " + mFrameRate + " FPS");
mFrameRate = 0;
}
LogUtil.i(TAG, "[END] onFrameDetected");
}
/**
* 切换到下一个动作时的回调方法
*
* @param lastActionType 上一个动作类型
* @param lastActionResult 上一个动作的检测结果
* @param newActionType 当前新生成的动作类型
* @param currentActionIndex 当前是第几个动作
* @param faceInfo 人脸的信息
*/
public void onActionChanged(int lastActionType, int lastActionResult, int newActionType, int
currentActionIndex, OliveappFaceInfo faceInfo) {
try {
// 更新提示文字
String hintText;
switch (newActionType) {
case FacialActionType.MOUTH_OPEN:
hintText = getString(R.string.oliveapp_step_hint_mouthopen);
break;
case FacialActionType.EYE_CLOSE:
hintText = getString(R.string.oliveapp_step_hint_eyeclose);
break;
case FacialActionType.HEAD_UP:
hintText = getString(R.string.oliveapp_step_hint_headup);
break;
default:
hintText = getString(R.string.oliveapp_step_hint_focus);
}
mAnimController.playHintTextAnimation(hintText);
mLocationArray = getFaceInfoLocation(newActionType, faceInfo);
mCurrentActionType = newActionType;
mAnimationHanlder.removeCallbacksAndMessages(null);
mAnimationHanlder.post(mActionAnimationTask);
} catch (Exception e) {
LogUtil.i(TAG, "changeToNextAction interrupt");
}
}
/**==========================================一些辅助函数==============================**/
/**
* 拿到当前动作对应的脸部坐标,用于做动画
*
* @param actionType 动作类型
* @param faceInfo 对应的人脸信息
* @return 脸部坐标数组
*/
private ArrayList<Pair<Double, Double>> getFaceInfoLocation(int actionType, OliveappFaceInfo
faceInfo) {
ArrayList<Pair<Double, Double>> result = new ArrayList<Pair<Double, Double>>();
switch (actionType) {
case FacialActionType.EYE_CLOSE: {
result.add(faceInfo.leftEye);
result.add(faceInfo.rightEye);
break;
}
case FacialActionType.MOUTH_OPEN: {
result.add(faceInfo.mouthCenter);
break;
}
case FacialActionType.HEAD_UP: {
result.add(faceInfo.chin);
break;
}
}
return result;
}
//========================根据设置决定本Activity要采用哪个layout=======================//
private int decideWhichLayout() {
int layout = R.layout.oliveapp_sample_liveness_detection_main_portrait_phone;
//选择布局文件
switch (SampleScreenDisplayHelper.getFixedOrientation(this)) {
case PORTRAIT:
if (SampleScreenDisplayHelper.ifThisIsPhone(this)) {
layout = R.layout.oliveapp_sample_liveness_detection_main_portrait_phone;
} else {
layout = R.layout.oliveapp_sample_liveness_detection_main_portrait_tablet;
}
break;
case LANDSCAPE:
if (!SampleScreenDisplayHelper.ifThisIsPhone(this)) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE);
layout = R.layout.oliveapp_sample_liveness_detection_main_landscape;
} else {
layout = R.layout.oliveapp_sample_liveness_detection_main_portrait_phone;
}
break;
}
return layout;
}
//从描述泌尿数文字转换成为昏暗阈值
public int getDarkLevelFromDesc(String desc) {
//对应关系如下:
//0:无
//1:低
//2:中
//3:高
switch (desc) {
case "无":
return 0;
case "低":
return 1;
case "中":
return 2;
case "高":
return 3;
default:
return 0;
}
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus) {
DisplayMetrics displaymetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
int height = displaymetrics.heightPixels;
int width = displaymetrics.widthPixels;
mXPercent = mCapFrame.getX() / width - 0.1f;
mYPercent = mCapFrame.getY() / height - 0.1f;
mWidthPercent = (float) mCapFrame.getWidth() / width + 0.1f;
mHeightPercent = (float) mCapFrame.getHeight() / height + 0.1f;
}
}
/////////////////// FOR DEBUG //////////////////////
private TextView mFrameRateText;
private long mLastTimestamp = System.currentTimeMillis();
private int mFrameRate = 0;
private static int classObjectCount = 0;
private void increaseClassObjectCount() {
// DEBUG: 检测是否有Activity泄漏
classObjectCount++;
LogUtil.i(TAG, "LivenessDetectionMainActivity classObjectCount onCreate: " +
classObjectCount);
// 预期现象是classObjectCount会在1~2之间抖动,如果classObjectCount一直在增长,很可能有内存泄漏
if (classObjectCount == 10) {
System.gc();
}
// Assert.assertTrue(classObjectCount < 10);
}
@Override
public void finalize() {
try {
super.finalize();
} catch (Throwable e) {
LogUtil.e(TAG, "无法完成finalize...", e);
}
// DEBUG: 检测是否有Activity泄漏。与increaseClassObjectCount对应
classObjectCount--;
LogUtil.i(TAG, "LivenessDetectionMainActivity classObjectCount finalize: " +
classObjectCount);
}
/**
* 播放动作动画和音频的Runnable
*/
private Runnable mActionAnimationTask = new Runnable() {
@Override
public void run() {
if (/*mAudioModule != null && */mAnimController != null) {
// mAudioModule.playAudio(LivenessDetectionMainActivity.this, FacialActionType
// .getStringResourceName(mCurrentActionType));
mAnimController.playActionAnimation(mCurrentActionType, mLocationArray);
mAnimationHanlder.postDelayed(this, 2500);
}
}
};
/**
* 播放预检动画和音频的Runnable
*/
private Runnable mPreHintAnimation = new Runnable() {
@Override
public void run() {
if (/*mAudioModule != null && */mAnimController != null) {
// mAudioModule.playAudio(LivenessDetectionMainActivity.this, FacialActionType
// .getStringResourceName(FacialActionType.CAPTURE));
mAnimController.playAperture();
mAnimationHanlder.postDelayed(this, 2500);
}
}
};
/**
* 算法初始化成功
*/
public void onInitializeSucc() {
}
public void onInitializeFail(Throwable e) {
}
/**
* 获取大礼包
* @return 大礼包
*/
/*protected LivenessDetectionFrames getLivenessDetectionPackage() {
return mVerificationController.getLivenessDetectionPackage();
}*/
}
package com.oliveapp.liveness.sample.register;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import com.oliveapp.liveness.sample.R;
public class SampleCameraResultActivity extends Activity{
public static final String TAG = SampleCameraResultActivity.class.getSimpleName();
public static final String EXTRA_IMAGE_CONTENT = "image_content";
public static final String EXTRA_FACE_EXISTS = "face_exists";
public static final String EXTRA_FACE_RECT = "face_rect";
private ImageView mImageView;
private Button mRetakeButton;
private Button mBackButton;
public static final int livenessMode = 4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample_register_result);
mImageView = (ImageView) findViewById(R.id.captureImageImageView);
mRetakeButton = (Button) findViewById(R.id.retakeButton);
mBackButton = (Button) findViewById(R.id.confirmButton);
Bundle result = getIntent().getExtras();
final int mode = result.getInt(SampleImageCaptureActivity.EXTRA_CAPTURE_MODE);
byte[] imageContent = result.getByteArray(EXTRA_IMAGE_CONTENT);
boolean faceExists = result.getBoolean(EXTRA_FACE_EXISTS);
Bitmap capturedImage = BitmapFactory.decodeByteArray(imageContent, 0, imageContent.length);
if (faceExists) {
Bitmap imageWithRect = capturedImage.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(imageWithRect);
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(10);
String rectString = result.getString(EXTRA_FACE_RECT);
Rect rect = Rect.unflattenFromString(rectString);
canvas.drawRect(rect, paint);
mImageView.setImageBitmap(imageWithRect);
} else {
mImageView.setImageBitmap(capturedImage);
}
//
if (livenessMode == mode) {
mRetakeButton.setVisibility(View.INVISIBLE);
}
mRetakeButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(SampleCameraResultActivity.this, SampleImageCaptureActivity.class);
i.putExtra(SampleImageCaptureActivity.EXTRA_CAPTURE_MODE, mode);
startActivity(i);
finish();
}
});
mBackButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
}
package com.oliveapp.liveness.sample.register;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.oliveapp.face.idcardcaptorsdk.captor.IDCardCaptor;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.libimagecapture.CaptureImageFragment;
import com.oliveapp.liveness.sample.R;
import com.oliveapp.liveness.sample.idcard_captor.SampleIdcardCaptorActivity;
public class SampleChooseCameraActivity extends Activity {
public static final String TAG = SampleChooseCameraActivity.class.getSimpleName();
private Button mIdCardButton;
private Button mSelfieButton;
private Button mIdcardFrontCaptureButton;
private Button mIdcardBackCaptureButton;
private IdcardCaptureListener mIdcardCaptureListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample_register);
mIdCardButton = (Button) findViewById(R.id.IDcard);
mSelfieButton = (Button) findViewById(R.id.Selfie);
mIdcardFrontCaptureButton = (Button) findViewById(R.id.IdcardFrontCapture);
mIdcardBackCaptureButton = (Button) findViewById(R.id.IdcardBackCapture);
/**
* 拍摄身份证正面,反面请使用CaptureImageFragment.CAPTURE_MODE_IDCARD_BACK
*/
mIdCardButton.setOnClickListener(
new CaptureImageListener(CaptureImageFragment.CAPTURE_MODE_IDCARD_FRONT));
/**
* 拍摄类登记照
*/
mSelfieButton.setOnClickListener(
new CaptureImageListener(CaptureImageFragment.CAPTURE_MODE_SELFIE));
mIdcardCaptureListener = new IdcardCaptureListener();
mIdcardFrontCaptureButton.setOnClickListener(mIdcardCaptureListener);
mIdcardBackCaptureButton.setOnClickListener(mIdcardCaptureListener);
requestPermission();
}
private class CaptureImageListener implements View.OnClickListener {
private int mCaptureType;
public CaptureImageListener(int captureMode) {
mCaptureType = captureMode;
}
@Override
public void onClick(View v) {
if (requestPermission()) {
Intent i = new Intent(SampleChooseCameraActivity.this, SampleImageCaptureActivity.class);
i.putExtra(SampleImageCaptureActivity.EXTRA_CAPTURE_MODE, mCaptureType);
startActivity(i);
}
}
}
private class IdcardCaptureListener implements View.OnClickListener {
@Override
public void onClick(View v) {
Intent i = new Intent(SampleChooseCameraActivity.this, SampleIdcardCaptorActivity.class);
/**
* 设置身份证识别正面还是反面
*/
int i1 = v.getId();
if (i1 == R.id.IdcardFrontCapture) {
i.putExtra(SampleIdcardCaptorActivity.EXTRA_CARD_TYPE, IDCardCaptor.CARD_TYPE_FRONT);
} else if (i1 == R.id.IdcardBackCapture) {
i.putExtra(SampleIdcardCaptorActivity.EXTRA_CARD_TYPE, IDCardCaptor.CARD_TYPE_BACK);
}
/**
* 设置捕获模式,共有三种模式模式:
* 1.SampleIdcardCaptorActivity.CAPTURE_MODE_AUTO 自动捕获模式
* 2.SampleIdcardCaptorActivity.CAPTURE_MODE_MANUAL 手动拍摄模式
* 3.SampleIdcardCaptorActivity.CAPTURE_MODE_MIXED 混合模式,首先尝试自动捕获,指定时间后,采取手动拍摄
* 在本例中,使用混合捕获模式,需要设置自动捕获持续时间,单位为秒,默认10秒
*/
i.putExtra(SampleIdcardCaptorActivity.EXTRA_CAPTURE_MODE, SampleIdcardCaptorActivity.CAPTURE_MODE_MIXED);
i.putExtra(SampleIdcardCaptorActivity.EXTRA_DURATION_TIME, 10);
if (requestPermission()) {
startActivity(i);
}
}
}
/**==============================请求相机权限=========================**/
private static final int PERMISSION_READ_EXTERNAL_STORAGE = 101;
private static final int PERMISSION_WRITE_EXTERNAL_STORAGE = 102;
private static final int PERMISSION_CAMERA = 103;
private boolean requestPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_WRITE_EXTERNAL_STORAGE);
return false;
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSION_READ_EXTERNAL_STORAGE);
return false;
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, PERMISSION_CAMERA);
return false;
}
return true;
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
try {
switch (requestCode) {
case PERMISSION_CAMERA: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
Toast.makeText(this, "没有摄像头权限我什么都做不了哦!", Toast.LENGTH_LONG).show();
}
break;
}
case PERMISSION_READ_EXTERNAL_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
Toast.makeText(this, "请打开存储读写权限,确保APP正常运行", Toast.LENGTH_LONG).show();
}
break;
}
case PERMISSION_WRITE_EXTERNAL_STORAGE: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
} else {
Toast.makeText(this, "请打开存储读写权限,确保APP正常运行", Toast.LENGTH_LONG).show();
}
break;
}
}
} catch (Exception e) {
LogUtil.e(TAG, "Failed to request Permission", e);
}
}
}
package com.oliveapp.liveness.sample.register;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.oliveapp.libcommon.utility.PackageNameManager;
import com.oliveapp.libimagecapture.CaptureImageFragment;
import com.oliveapp.libimagecapture.OnImageCapturedEventListener;
import com.oliveapp.libimagecapture.datatype.DetectedRect;
import com.oliveapp.liveness.sample.R;
public class SampleImageCaptureActivity extends Activity implements OnImageCapturedEventListener {
public static final String TAG = SampleImageCaptureActivity.class.getSimpleName();
public static final String EXTRA_CAPTURE_MODE = "capture_mode";
private CaptureImageFragment mCaptureImageFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
if (!PackageNameManager.isPackageNameSet()) {
PackageNameManager.setPackageName(getPackageName());
}
PackageNameManager.setPackageName(PackageNameManager.getPackageName());
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sample_image_capture);
attachUserImageRegistractionFragment();
}
private void attachUserImageRegistractionFragment() {
FragmentManager mFragmentManager = getFragmentManager();
CaptureImageFragment userImageRegisterFragment = (CaptureImageFragment) mFragmentManager.findFragmentByTag(CaptureImageFragment.TAG);
if (userImageRegisterFragment == null) {
int captureType = getIntent().getExtras().getInt(EXTRA_CAPTURE_MODE, CaptureImageFragment.CAPTURE_MODE_IDCARD_FRONT);
userImageRegisterFragment = CaptureImageFragment.newInstance(captureType);
FragmentTransaction ft = mFragmentManager.beginTransaction();
ft.add(R.id.imageCaptureMainLayout, userImageRegisterFragment, CaptureImageFragment.TAG);
ft.commit();
} else {
if (userImageRegisterFragment.isAdded()) {
Log.i(TAG, "user image register fragment already attached");
}
}
userImageRegisterFragment.setArgs(this, this);
mCaptureImageFragment = userImageRegisterFragment;
}
@Override
public void OnImageCaptured(byte[] imageContent, DetectedRect faceRect) {
boolean faceExists = (faceRect != null);
Intent i = new Intent(this, SampleCameraResultActivity.class);
i.putExtra(EXTRA_CAPTURE_MODE, getIntent().getExtras().getInt(EXTRA_CAPTURE_MODE, CaptureImageFragment.CAPTURE_MODE_IDCARD_FRONT));
i.putExtra(SampleCameraResultActivity.EXTRA_IMAGE_CONTENT, imageContent);
i.putExtra(SampleCameraResultActivity.EXTRA_FACE_EXISTS, faceExists);
if (faceExists) {
i.putExtra(SampleCameraResultActivity.EXTRA_FACE_RECT, faceRect.rect.flattenToString());
}
startActivity(i);
finish();
}
}
package com.oliveapp.liveness.sample.uicomponents;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.FrameLayout;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.libcommon.utility.PackageNameManager;
import com.oliveapp.liveness.sample.R;
import com.oliveapp.liveness.sample.utils.SampleScreenDisplayHelper;
public class FixedAspectLayout extends FrameLayout {
private float mHWAspect = 1.0f;
private final static int FIX_HEIGHT = 1;
private final static int FIX_WIDTH = 2;
private int mFixMode = 1;
// .. alternative constructors omitted
public FixedAspectLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
@SuppressWarnings("ResourceType")
private void init(Context context, AttributeSet attrs) {
int aspectRatioId = R.attr.oliveapp_aspectRatio;
int fixModeId = R.attr.oliveapp_fixMode;
int attrArray[] = {aspectRatioId, fixModeId};
TypedArray array = context.obtainStyledAttributes(attrs, attrArray);
/**
* 改用动态获取比例来适应不同屏幕
*/
if ((SampleScreenDisplayHelper.getFixedOrientation(context) == SampleScreenDisplayHelper.OrientationType.LANDSCAPE) && !SampleScreenDisplayHelper.ifThisIsPhone(context)) {
mHWAspect = (float) (1 / SampleScreenDisplayHelper.getScreenScale(context));
} else {
mHWAspect = (float) SampleScreenDisplayHelper.getScreenScale(context);
}
mFixMode = array.getInt(1, 1); // First Parameter represents FixMode, cannot get styleableId dynamically
array.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int w = MeasureSpec.getSize(widthMeasureSpec);
int h = MeasureSpec.getSize(heightMeasureSpec);
if (w == 0) {
h = 0;
} else {
switch (mFixMode) {
case FIX_HEIGHT:
w = (int) (h / mHWAspect);
break;
case FIX_WIDTH:
h = (int) (w * mHWAspect);
break;
default:
w = (int) (h / mHWAspect);
}
}
super.onMeasure(
MeasureSpec.makeMeasureSpec(w,
MeasureSpec.getMode(widthMeasureSpec)),
MeasureSpec.makeMeasureSpec(h,
MeasureSpec.getMode(heightMeasureSpec)));
}
}
package com.oliveapp.liveness.sample.utils;
import android.content.Context;
import android.media.MediaPlayer;
import android.net.Uri;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.libcommon.utility.PackageNameManager;
import java.io.IOException;
/**
* Created by jthao on 1/13/16.
*/
public class AudioModule {
private static final String TAG = AudioModule.class.getSimpleName();
private MediaPlayer mAudioPlayer = new MediaPlayer();
public void playAudio(Context context, String audioResourceName)
{
String packageName = PackageNameManager.getPackageName();
int rawId = context.getResources().getIdentifier(audioResourceName, "raw", packageName);
Uri audioUri = Uri.parse("android.resource://" + packageName + "/" + rawId);
try {
if (mAudioPlayer != null && mAudioPlayer.isPlaying())
mAudioPlayer.stop();
mAudioPlayer.reset();
mAudioPlayer.setDataSource(context, audioUri);
mAudioPlayer.prepare();
mAudioPlayer.start();
} catch (IOException e) {
LogUtil.e(TAG, "fail to set data source for audio player", e);
} catch (NullPointerException e) {
LogUtil.e(TAG, "", e);
} catch (IllegalStateException e) {
LogUtil.e(TAG, "fail to play audio type: ", e);
}
}
public boolean isPlaying() {
if (mAudioPlayer != null) {
return mAudioPlayer.isPlaying();
}
return false;
}
public void release() {
try {
mAudioPlayer.stop();
mAudioPlayer.release();
mAudioPlayer = null;
} catch (Exception e) {
LogUtil.e(TAG, "Fail to release", e);
}
}
}
package com.oliveapp.liveness.sample.utils;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.support.percent.PercentLayoutHelper;
import android.support.percent.PercentRelativeLayout;
import android.util.Pair;
import android.util.StringBuilderPrinter;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.oliveapp.face.livenessdetectorsdk.livenessdetector.datatype.FacialActionType;
import com.oliveapp.face.livenessdetectorsdk.livenessdetector.datatype.OliveappFaceInfo;
import com.oliveapp.libcommon.utility.LogUtil;
import com.oliveapp.liveness.sample.R;
import java.util.ArrayList;
/**
* Created by cli on 1/10/17.
* 管理活检过程的3个动画效果的实现
*/
public class OliveappAnimationHelper {
public static final String TAG = OliveappAnimationHelper.class.getSimpleName();
private Activity mContext;
private ImageView mLeftBorder;
private ImageView mRightBorder;
private TextView mHintText;
private ImageView mDetectFrameSurround;
private PercentRelativeLayout mDetectLayout;
private ImageView mLeftEyeImage;
private ImageView mRightEyeImage;
private ImageView mChinImage;
private ImageView mChinUpImage;
private ImageView mMouthCloseImage;
private ImageView mMouthOpenImage;
private final long MIN_MS = 250;
public OliveappAnimationHelper(Activity context) {
this.mContext = context;
init();
}
public void init() {
mLeftBorder = (ImageView) mContext.findViewById(R.id.oliveapp_detected_hint_left_border);
mRightBorder = (ImageView) mContext.findViewById(R.id.oliveapp_detected_hint_right_border);
mHintText = (TextView) mContext.findViewById(R.id.oliveapp_detected_hint_text);
mDetectFrameSurround = (ImageView) mContext.findViewById(R.id.oliveapp_start_frame);
mDetectLayout = (PercentRelativeLayout) mContext.findViewById(R.id.oliveapp_detected_layout);
}
/**
* 提示正对屏幕的动画
* 只有在有预检的时候才会触发
* 文字两边的黄色小边框和检测框的四角发生位移
* 使用组合动画
*/
public void playAperture() {
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator leftBorderAnim = ObjectAnimator.ofFloat(mLeftBorder, "translationX", 0f, -25f, 0f);
ObjectAnimator rightBorderAnim = ObjectAnimator.ofFloat(mRightBorder, "translationX", 0f, 25f, 0f);
ObjectAnimator detectFrameSurroundAnimX = ObjectAnimator.ofFloat(mDetectFrameSurround, "scaleX", 1, 1.2f, 1f);
ObjectAnimator detectFrameSurroundAnimY = ObjectAnimator.ofFloat(mDetectFrameSurround, "scaleY", 1, 1.2f, 1f);
animatorSet.setDuration(1000);
animatorSet.playTogether(leftBorderAnim, rightBorderAnim, detectFrameSurroundAnimX, detectFrameSurroundAnimY);
animatorSet.start();
}
/**
* 提示语的动画
*/
public void playHintTextAnimation(String hintText) {
//前半段动画
AnimatorSet formerBlinkAnimatorSet = new AnimatorSet();
ObjectAnimator formerHintTextAnim = ObjectAnimator.ofFloat(mHintText, "scaleX", 1f, 0f);
ObjectAnimator formerLeftBorderAnim = ObjectAnimator.ofFloat(mLeftBorder, "translationX", 0f, 100f);
ObjectAnimator formerRightBorderAnim = ObjectAnimator.ofFloat(mRightBorder, "translationX", 0f, -100f);
formerBlinkAnimatorSet.playTogether(formerHintTextAnim, formerLeftBorderAnim, formerRightBorderAnim);
formerBlinkAnimatorSet.setDuration(250);
formerBlinkAnimatorSet.start();
final String finalHintText = hintText;
formerBlinkAnimatorSet.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
mHintText.setText(finalHintText);
//后半段动画
AnimatorSet latterBlinkAnimatorSet = new AnimatorSet();
ObjectAnimator latterHintTextAnim = ObjectAnimator.ofFloat(mHintText, "scaleX", 0f, 1f);
ObjectAnimator latterLeftBorderAnim = ObjectAnimator.ofFloat(mLeftBorder, "translationX", 100f, 0f);
ObjectAnimator latterRightBorderAnim = ObjectAnimator.ofFloat(mRightBorder, "translationX", -100f, 0f);
latterBlinkAnimatorSet.playTogether(latterHintTextAnim, latterLeftBorderAnim, latterRightBorderAnim);
latterBlinkAnimatorSet.setDuration(250);
latterBlinkAnimatorSet.start();
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
}
public void playActionAnimation(int actionType, ArrayList<Pair<Double, Double>> locationArray) {
mDetectLayout.removeView(mMouthCloseImage);
mDetectLayout.removeView(mMouthOpenImage);
mDetectLayout.removeView(mLeftEyeImage);
mDetectLayout.removeView(mRightEyeImage);
mDetectLayout.removeView(mChinImage);
mDetectLayout.removeView(mChinUpImage);
switch (actionType) {
case FacialActionType.EYE_CLOSE:{
startEyeAnim(locationArray);
break;
}
case FacialActionType.MOUTH_OPEN: {
startMouthAnim(locationArray);
break;
}
case FacialActionType.HEAD_UP: {
startChinAnim(locationArray);
}
}
}
public void startMouthAnim(ArrayList<Pair<Double, Double>> locationArray) {
Pair<Double, Double> mouthLocation = locationArray.get(0);
if (mDetectLayout == null) {
mDetectLayout = (PercentRelativeLayout) mContext.findViewById(R.id.oliveapp_detected_layout);
}
/**
* 创建要显示的ImageView对象
*/
mMouthCloseImage = new ImageView(mContext);
mMouthOpenImage = new ImageView(mContext);
mMouthCloseImage.setImageResource(R.mipmap.oliveapp_mouth_close);
mMouthOpenImage.setImageResource(R.mipmap.oliveapp_mouth_open);
mMouthCloseImage.setScaleType(ImageView.ScaleType.FIT_XY);
mMouthOpenImage.setScaleType(ImageView.ScaleType.FIT_XY);
PercentRelativeLayout.LayoutParams detectFrameParams = (PercentRelativeLayout.LayoutParams) mDetectFrameSurround.getLayoutParams();
float detectFrameWidthPercent = detectFrameParams.getPercentLayoutInfo().widthPercent;
float detectFrameHeightPercent = detectFrameParams.getPercentLayoutInfo().heightPercent;
float detectFrameLeftMarginPercent = detectFrameParams.getPercentLayoutInfo().leftMarginPercent;
float detectFrameTopMarginPercent = detectFrameParams.getPercentLayoutInfo().topMarginPercent;
/**
* 布局闭嘴动画
*/
PercentRelativeLayout.LayoutParams lpMouth = new PercentRelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
PercentLayoutHelper.PercentLayoutInfo mouthInfo= lpMouth.getPercentLayoutInfo();
mouthInfo.widthPercent = detectFrameWidthPercent / 4 ;
mouthInfo.heightPercent = detectFrameHeightPercent / 8;
mouthInfo.leftMarginPercent = (1.f - (float) mouthLocation.first.doubleValue()) - 0.1f;
mouthInfo.topMarginPercent = ((float) mouthLocation.second.doubleValue());
mMouthCloseImage.requestLayout();
mMouthOpenImage.requestLayout();
mMouthCloseImage.setLayoutParams(lpMouth);
mMouthOpenImage.setLayoutParams(lpMouth);
mDetectLayout.addView(mMouthCloseImage);
/**
* 定义一个总的AnimatorSet
*/
AnimatorSet mouthAnim = new AnimatorSet();
/**
* 闭嘴的动画
*/
ObjectAnimator mouthCloseXAnimator = ObjectAnimator.ofFloat(mMouthCloseImage, "scaleX", 2.f, 1.0f);
final ObjectAnimator mouchCloseYAnimator = ObjectAnimator.ofFloat(mMouthCloseImage, "scaleY", 2.f, 1.0f);
ObjectAnimator mouthCloseAlphaAnimator = ObjectAnimator.ofFloat(mMouthCloseImage, "alpha", 0.f, 1.0f);
AnimatorSet mouthCloseAnimation = new AnimatorSet();
mouthCloseAnimation.setDuration(MIN_MS * 2);
mouthCloseAnimation.playTogether(mouthCloseXAnimator, mouchCloseYAnimator, mouthCloseAlphaAnimator);
mouthCloseAnimation.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
mDetectLayout.removeView(mMouthCloseImage);
mDetectLayout.addView(mMouthOpenImage);
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
/**
* 张嘴的动画
*/
ObjectAnimator mouthOpenXAnimator = ObjectAnimator.ofFloat(mMouthOpenImage, "scaleX", 1.f, 2.0f);
ObjectAnimator mouchOpenYAnimator = ObjectAnimator.ofFloat(mMouthOpenImage, "scaleY", 1.f, 2.0f);
ObjectAnimator mouthOpenAlphaAnimator = ObjectAnimator.ofFloat(mMouthOpenImage, "alpha", 1.f, 0.f);
AnimatorSet mouthOpenAnimation = new AnimatorSet();
mouthOpenAnimation.setDuration(MIN_MS * 2);
mouthOpenAnimation.playTogether(mouthOpenXAnimator, mouchOpenYAnimator, mouthOpenAlphaAnimator);
mouthAnim.play(mouthCloseAnimation).before(mouthOpenAnimation);
mouthAnim.start();
}
public void startChinAnim(ArrayList<Pair<Double, Double>> locationArray) {
Pair<Double, Double> chinLocation = locationArray.get(0);
if (mDetectLayout == null) {
mDetectLayout = (PercentRelativeLayout) mContext.findViewById(R.id.oliveapp_detected_layout);
}
/**
* 创建要显示的ImageView对象
*/
mChinImage = new ImageView(mContext);
mChinUpImage = new ImageView(mContext);
mChinImage.setImageResource(R.mipmap.oliveapp_chin);
mChinUpImage.setImageResource(R.mipmap.oliveapp_chin_up);
mChinImage.setScaleType(ImageView.ScaleType.FIT_XY);
mChinUpImage.setScaleType(ImageView.ScaleType.FIT_XY);
PercentRelativeLayout.LayoutParams detectFrameParams = (PercentRelativeLayout.LayoutParams) mDetectFrameSurround.getLayoutParams();
float detectFrameWidthPercent = detectFrameParams.getPercentLayoutInfo().widthPercent;
float detectFrameHeightPercent = detectFrameParams.getPercentLayoutInfo().heightPercent;
float detectFrameLeftMarginPercent = detectFrameParams.getPercentLayoutInfo().leftMarginPercent;
float detectFrameTopMarginPercent = detectFrameParams.getPercentLayoutInfo().topMarginPercent;
/**
* 布局下巴提示图片
*/
PercentRelativeLayout.LayoutParams lpChin = new PercentRelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
PercentLayoutHelper.PercentLayoutInfo chinInfo= lpChin.getPercentLayoutInfo();
chinInfo.widthPercent = detectFrameWidthPercent / 4 * 3;
chinInfo.heightPercent = detectFrameHeightPercent / 2;
lpChin.addRule(RelativeLayout.ALIGN_BOTTOM, R.id.oliveapp_start_frame);
lpChin.addRule(RelativeLayout.CENTER_HORIZONTAL);
mChinImage.requestLayout();
/**
* 布局箭头
*/
PercentRelativeLayout.LayoutParams lpChinUp = new PercentRelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
PercentLayoutHelper.PercentLayoutInfo chinUpInfo= lpChinUp.getPercentLayoutInfo();
chinUpInfo.widthPercent = detectFrameWidthPercent / 7;
chinUpInfo.heightPercent = detectFrameHeightPercent / 5;
chinUpInfo.topMarginPercent = detectFrameTopMarginPercent + detectFrameHeightPercent / 4 * 3;
lpChinUp.addRule(RelativeLayout.CENTER_HORIZONTAL);
mChinUpImage.requestLayout();
/**
* 设置布局参数, 添加到布局中
*/
mChinImage.setLayoutParams(lpChin);
mChinUpImage.setLayoutParams(lpChinUp);
mDetectLayout.addView(mChinImage);
mDetectLayout.addView(mChinUpImage);
/**
* 定义一个总的AnimatorSet
*/
AnimatorSet headUpAnim = new AnimatorSet();
/**
* 缩放的动画
*/
ObjectAnimator chinXAnimator = ObjectAnimator.ofFloat(mChinImage, "scaleX", 1.5f, 1.0f);
ObjectAnimator chinYAnimator = ObjectAnimator.ofFloat(mChinImage, "scaleY", 1.5f, 1.0f);
ObjectAnimator chinAlphaAnimator = ObjectAnimator.ofFloat(mChinImage, "alpha", 0.f, 1.0f);
AnimatorSet chinAnimation = new AnimatorSet();
chinAnimation.setDuration(MIN_MS * 2);
chinAnimation.playTogether(chinXAnimator, chinYAnimator, chinAlphaAnimator);
ObjectAnimator chinUpAnimator = ObjectAnimator.ofFloat(mChinUpImage, "alpha", 0.f, 1.f);
chinUpAnimator.setDuration(MIN_MS * 2);
chinUpAnimator.setRepeatCount(-1);
chinUpAnimator.setRepeatMode(ValueAnimator.REVERSE);
/**
* 设置缩放的顺序
*/
headUpAnim.play(chinAnimation).before(chinUpAnimator);
headUpAnim.start();
}
/**
* 检测到眼睛的定位点的动画
* 眼睛部位有icon的位移
* 1,创建ImageView对象,根据坐标赋值并添加到布局中
* 2,创建动画
*/
public void startEyeAnim(ArrayList<Pair<Double, Double>> locationArray) {
/**
* 拿到眼睛位置距离左和上的百分比
*/
Pair<Double, Double> leftPair = locationArray.get(0);
Pair<Double, Double> rightPair = locationArray.get(1);
if (mDetectLayout == null) {
mDetectLayout = (PercentRelativeLayout) mContext.findViewById(R.id.oliveapp_detected_layout);
}
/**
* 创建要显示的ImageView对象
*/
mLeftEyeImage = new ImageView(mContext);
mRightEyeImage = new ImageView(mContext);
mLeftEyeImage.setImageResource(R.mipmap.oliveapp_detect_eye_location);
mRightEyeImage.setImageResource(R.mipmap.oliveapp_detect_eye_location);
mLeftEyeImage.setScaleType(ImageView.ScaleType.FIT_XY);
mRightEyeImage.setScaleType(ImageView.ScaleType.FIT_XY);
/**
* 布局左眼
*/
PercentRelativeLayout.LayoutParams lpLeft = new PercentRelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
PercentLayoutHelper.PercentLayoutInfo leftInfo= lpLeft.getPercentLayoutInfo();
leftInfo.widthPercent = 0.15f;
leftInfo.heightPercent = 0.1f;
leftInfo.leftMarginPercent = (1.f - (float) leftPair.first.doubleValue()) - 0.1f;
leftInfo.topMarginPercent = ((float) leftPair.second.doubleValue()) - 0.05f ;
mLeftEyeImage.requestLayout();
/**
* 布局右眼
*/
PercentRelativeLayout.LayoutParams lpRight = new PercentRelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
PercentLayoutHelper.PercentLayoutInfo rightInfo= lpRight.getPercentLayoutInfo();
rightInfo.widthPercent = 0.15f;
rightInfo.heightPercent = 0.1f;
rightInfo.leftMarginPercent = (1.f - (float) rightPair.first.doubleValue()) - 0.1f;
rightInfo.topMarginPercent = ((float) rightPair.second.doubleValue()) - 0.05f;
mRightEyeImage.requestLayout();
/**
* 设置布局参数, 添加到布局中
*/
mLeftEyeImage.setLayoutParams(lpLeft);
mRightEyeImage.setLayoutParams(lpRight);
mDetectLayout.addView(mLeftEyeImage);
mDetectLayout.addView(mRightEyeImage);
/**
* 定义一个总的AnimatorSet
*/
AnimatorSet eyeAnim = new AnimatorSet();
/**
* 管理缩放的AnimatorSet
*/
AnimatorSet scaleAnim = new AnimatorSet();
/**
* 管理透明度的AnimatorSet
*/
AnimatorSet alphaAnim = new AnimatorSet();
/**
* 缩放动画的具体实现
* 第一阶段:眼部图片的缩放
*/
ObjectAnimator leftScaleAnimatorX1 = ObjectAnimator.ofFloat(mLeftEyeImage, "scaleX", 1f, 0.35f);
ObjectAnimator leftScaleAnimatorY1 = ObjectAnimator.ofFloat(mLeftEyeImage, "scaleY", 1f, 0.35f);
ObjectAnimator rightScaleAnimatorX1 = ObjectAnimator.ofFloat(mRightEyeImage, "scaleX", 1f, 0.35f);
ObjectAnimator rightScaleAnimatorY1 = ObjectAnimator.ofFloat(mRightEyeImage, "scaleY", 1f, 0.35f);
AnimatorSet scaleAnimatorSet1 = new AnimatorSet();
scaleAnimatorSet1.setDuration(MIN_MS * 2);
scaleAnimatorSet1.playTogether(leftScaleAnimatorX1, leftScaleAnimatorY1, rightScaleAnimatorX1, rightScaleAnimatorY1);
/**
* 第二阶段的缩放
*/
ObjectAnimator leftScaleAnimatorX2 = ObjectAnimator.ofFloat(mLeftEyeImage, "scaleX", 0.35f, 0.6f);
ObjectAnimator leftScaleAnimatorY2 = ObjectAnimator.ofFloat(mLeftEyeImage, "scaleY", 0.35f, 0.6f);
ObjectAnimator rightScaleAnimatorX2 = ObjectAnimator.ofFloat(mRightEyeImage, "scaleX", 0.35f, 0.6f);
ObjectAnimator rightScaleAnimatorY2 = ObjectAnimator.ofFloat(mRightEyeImage, "scaleY", 0.35f, 0.6f);
AnimatorSet scaleAnimatorSet2 = new AnimatorSet();
scaleAnimatorSet2.setDuration(MIN_MS * 2);
scaleAnimatorSet2.playTogether(leftScaleAnimatorX2, leftScaleAnimatorY2, rightScaleAnimatorX2, rightScaleAnimatorY2);
/**
* 第三阶段的缩放
*/
ObjectAnimator leftScaleAnimatorX3 = ObjectAnimator.ofFloat(mLeftEyeImage, "scaleX", 0.6f, 0.3f);
ObjectAnimator leftScaleAnimatorY3 = ObjectAnimator.ofFloat(mLeftEyeImage, "scaleY", 0.6f, 0.3f);
ObjectAnimator rightScaleAnimatorX3 = ObjectAnimator.ofFloat(mRightEyeImage, "scaleX", 0.6f, 0.3f);
ObjectAnimator rightScaleAnimatorY3 = ObjectAnimator.ofFloat(mRightEyeImage, "scaleY", 0.6f, 0.3f);
AnimatorSet scaleAnimatorSet3 = new AnimatorSet();
scaleAnimatorSet3.setDuration(MIN_MS * 2);
scaleAnimatorSet3.playTogether(leftScaleAnimatorX3, leftScaleAnimatorY3, rightScaleAnimatorX3, rightScaleAnimatorY3);
/**
* 设置缩放的顺序
*/
scaleAnim.play(scaleAnimatorSet1).before(scaleAnimatorSet2).before(scaleAnimatorSet3);
/**
* 透明度动画具体实现
* 第一阶段
*/
ObjectAnimator leftAlphaAnimator1 = ObjectAnimator.ofFloat(mLeftEyeImage, "alpha", 0f, 1f);
ObjectAnimator rightAlphaAnimator1 = ObjectAnimator.ofFloat(mRightEyeImage, "alpha", 0f, 1f);
AnimatorSet alphaAnimatorSet1 = new AnimatorSet();
alphaAnimatorSet1.setDuration(MIN_MS * 2);
alphaAnimatorSet1.playTogether(leftAlphaAnimator1, rightAlphaAnimator1);
/**
* 第二阶段
*/
ObjectAnimator leftAlphaAnimator2 = ObjectAnimator.ofFloat(mLeftEyeImage, "alpha", 1f, 0f);
ObjectAnimator rightAlphaAnimator2 = ObjectAnimator.ofFloat(mRightEyeImage, "alpha", 1f, 0f);
AnimatorSet alphaAnimatorSet2 = new AnimatorSet();
alphaAnimatorSet2.setDuration(MIN_MS * 2);
alphaAnimatorSet2.playTogether(leftAlphaAnimator2, rightAlphaAnimator2);
/**
* 设置透明度变化顺序
*/
alphaAnim.play(alphaAnimatorSet2).after(MIN_MS * 2).after(alphaAnimatorSet1);
/**
* 开启动画
*/
eyeAnim.playTogether(scaleAnim, alphaAnim);
eyeAnim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
}
@Override
public void onAnimationEnd(Animator animator) {
sweepUp();
}
@Override
public void onAnimationCancel(Animator animator) {
}
@Override
public void onAnimationRepeat(Animator animator) {
}
});
eyeAnim.start();
}
/**
* 清理动画相关的资源
*/
public void sweepUp() {
if (mDetectLayout != null) {
if (mLeftEyeImage != null) {
mDetectLayout.removeView(mLeftEyeImage);
mLeftEyeImage = null;
}
if (mRightEyeImage != null) {
mDetectLayout.removeView(mRightEyeImage);
mRightEyeImage = null;
}
}
}
}
package com.oliveapp.liveness.sample.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
/**
* Created by cli on 1/10/17.
*/
public class SampleScreenDisplayHelper {
public static String TAG = SampleScreenDisplayHelper.class.getSimpleName();
public static final double MIN_TABLET_SIZE = 7.0;
/**
* 设置设备是显示横屏还是竖屏
* OrientationType枚举中有两种选项
* PORTRAIT代表竖屏
* LANDSCAPE代表横屏
*/
public enum OrientationType {
PORTRAIT, LANDSCAPE
}
/**
* 请在这里设置决定要采用的屏幕方向
* 默认都是竖屏
* 若要自定义,请重写getFixedOrientation(Context)方法
*/
public static OrientationType getFixedOrientation(Context context) {
/**
* 手机只有竖屏,平板根据摄像头位置可以设置横屏或者竖屏
* 若要设置横屏可返回OrientationType.LANDSCAPE
* 然后在具体的Activity的decideWhichLayout()方法中返回相应的layout值;
*/
if (ifThisIsPhone(context)) {
return OrientationType.PORTRAIT;
} else {
/**
* 以下代码是为了配合设置功能,集成时可以删除
*/
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
boolean isDebug = sharedPrefs.getBoolean("pref_debug_mode", false);
if (isDebug) {
boolean padLandscape = sharedPrefs.getBoolean("pref_pad_landscape", false);
if (padLandscape) {
return OrientationType.LANDSCAPE;
} else {
return OrientationType.PORTRAIT;
}
}
/**
* 以上代码是为了配合设置功能,集成时可以删除
*/
return OrientationType.PORTRAIT;
}
}
/**
* 判断本机是手机还是平板
* 若是手机,返回true
*/
public static boolean ifThisIsPhone(Context context) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
int widthPixels = dm.widthPixels;
int heightPixels = dm.heightPixels;
double diagonalPixels = Math.sqrt(new Double(widthPixels * widthPixels + heightPixels * heightPixels));
double dpi = dm.densityDpi;
double physicalSize = diagonalPixels / dpi;
double scale = new Double(heightPixels) / new Double(widthPixels);
double standard_16_9 = new Double(16).doubleValue() / new Double(9).doubleValue();
double standard_4_3 = new Double(4).doubleValue() / new Double(3).doubleValue();
double acceptable = 0.2;
if (physicalSize > MIN_TABLET_SIZE) {
return false;
} else {
if (Math.abs(scale - standard_16_9) < acceptable) {
return true;
}
return false;
}
}
/**
* 获取屏幕比例
* @param context
* @return
*/
public static double getScreenScale(Context context) {
DisplayMetrics dm = context.getResources().getDisplayMetrics();
int widthPixels = dm.widthPixels;
int heightPixels = dm.heightPixels;
double scale = new Double(heightPixels) / new Double(widthPixels);
return scale;
}
}
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<solid android:color="#ff00427d"/>
</shape>
</item>
<item android:state_selected="true">
<shape>
<solid android:color="#ff005aaa"/>
</shape>
</item>
<item android:state_enabled="false">
<shape>
<solid android:color="#80005aaa"/>
</shape>
</item>
<item>
<shape>
<solid android:color="#ff005aaa"/>
</shape>
</item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:useLevel="true"
android:innerRadiusRatio="2.7"
android:thickness="4dp"
android:shape="ring">
<!--<stroke android:width="1dp" android:color="#07ADD0"/>-->
<solid android:color="#02ADCF"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape
android:useLevel="false"
android:shape="oval">
<solid android:color="#5DC6E2" />
</shape>
</item>
<item>
<shape
android:useLevel="false"
android:innerRadiusRatio="2.7"
android:thickness="4dp"
android:shape="ring">
<!--<solid android:color="#02ADCF" />-->
<solid android:color="#ffffff" />
</shape>
</item>
</layer-list>
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:useLevel="false"
android:innerRadiusRatio="2.7"
android:thickness="4dp"
android:shape="oval">
<stroke android:width="1dp" android:color="#5DC6E2"/>
<solid android:color="#FF4D4D4D"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape>
<solid android:color="#ff00427d"/>
</shape>
</item>
<item android:state_selected="true">
<shape>
<solid android:color="#ff005aaa"/>
</shape>
</item>
<item android:state_enabled="false">
<shape>
<solid android:color="#80005aaa"/>
</shape>
</item>
<item>
<shape>
<solid android:color="#ff005aaa"/>
</shape>
</item>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<!-- 橙色人脸框,仅供debug用,非产品需求 -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:color="@color/navy"
android:width="2dp"/>
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/oliveapp_liveness_finish_button" android:state_pressed="false"/>
<item android:drawable="@mipmap/oliveapp_liveness_finish_button_click" android:state_pressed="true"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/oliveapp_liveness_finish_tablet" android:state_pressed="false"/>
<item android:drawable="@mipmap/oliveapp_liveness_finish_click_tablet" android:state_pressed="true"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/oliveapp_liveness_finish_retry" android:state_pressed="false"/>
<item android:drawable="@mipmap/oliveapp_liveness_finish_retry_click" android:state_pressed="true"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@mipmap/oliveapp_liveness_finish_retry_tablet" android:state_pressed="false"/>
<item android:drawable="@mipmap/oliveapp_liveness_finish_retry_click_tablet" android:state_pressed="true"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@mipmap/oliveapp_liveness_return_click"/>
<item android:state_pressed="false" android:drawable="@mipmap/oliveapp_liveness_return"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:drawable="@mipmap/oliveapp_liveness_finish_return_click_tablet"/>
<item android:state_pressed="false" android:drawable="@mipmap/oliveapp_liveness_finish_return_tablet"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:drawable="@mipmap/oliveapp_start_normal"/>
<item android:state_pressed="true" android:drawable="@mipmap/oliveapp_start_click"/>
</selector>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false" android:drawable="@mipmap/oliveapp_start_tablet"/>
<item android:state_pressed="true" android:drawable="@mipmap/oliveapp_start_click_tablet"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/checkbox_unchecked"
android:state_checked="false"
android:state_enabled="true"/>
<item
android:drawable="@drawable/checkbox_checked"
android:state_checked="true"
android:state_enabled="true"/>
<item
android:drawable="@drawable/checkbox_disable_unchecked"
android:state_checked="false"
android:state_enabled="false"/>
<item
android:drawable="@drawable/checkbox_disable_checked"
android:state_checked="true"
android:state_enabled="false"/>
</selector>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<selector
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:drawable="@color/itemdisabled" />
<item android:state_enabled="false" android:drawable="@color/itemdisabled" />
<item android:state_enabled="true" android:state_pressed="true" android:drawable="@color/itemSelectColor" />
<item android:state_focused="true" android:state_enabled="true" android:drawable="@color/itemSelectColor" />
<item android:state_enabled="true" android:state_selected="true" android:drawable="@color/itemSelectColor" />
<item android:drawable="@color/itemBgColor" />
</selector>
\ No newline at end of file
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.oliveapp.liveness.sample.idcard_captor.SampleIdcardActivity">
</RelativeLayout>
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ImageCaptureActivity"
android:id="@+id/imageCaptureMainLayout">
</RelativeLayout>
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/oliveapp_activity_vertical_margin"
android:paddingLeft="@dimen/oliveapp_activity_horizontal_margin"
android:paddingRight="@dimen/oliveapp_activity_horizontal_margin"
android:paddingTop="@dimen/oliveapp_activity_vertical_margin"
android:background="@color/colorDefaultBackground"
tools:context=".SampleLaunchActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/titleText"
android:id="@+id/titleTextView"
android:layout_alignParentTop="true"
android:layout_marginTop="70dp"
android:layout_centerHorizontal="true"
android:textSize="40sp"
android:textColor="@color/colorWhite"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="@string/oliveapp_version"
android:textColor="@color/colorWhite"
android:textSize="20sp" />
<!--<TextView-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:textAppearance="?android:attr/textAppearanceLarge"-->
<!--android:text="@string/subtitleText"-->
<!--android:id="@+id/subtitleTextView"-->
<!--android:layout_below="@+id/titleTextView"-->
<!--android:layout_alignLeft="@+id/titleTextView"-->
<!--android:layout_alignStart="@+id/titleTextView" />-->
<Button
android:layout_width="match_parent"
android:layout_height="46dp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:text="@string/hintCamera"
android:id="@+id/startButton"
android:layout_centerHorizontal="true"
android:layout_below="@+id/titleTextView"
android:layout_marginTop="100dp"
android:background="@drawable/oliveapp_button_background"
android:textColor="#ffffff"
android:textSize="20sp" />
<Button
android:layout_width="match_parent"
android:layout_height="46dp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:text="@string/livenessButtonText"
android:id="@+id/livenessButton"
android:background="@drawable/oliveapp_button_background"
android:textColor="#ffffff"
android:textSize="20sp"
android:layout_below="@+id/startButton"
android:layout_marginTop="20dp"
android:layout_centerHorizontal="true" />
<Button
android:layout_width="match_parent"
android:layout_height="46dp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:text="@string/settingButtonText"
android:id="@+id/settingButton"
android:background="@drawable/oliveapp_button_background"
android:textColor="#ffffff"
android:textSize="20sp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="60dp" />
</RelativeLayout>
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/oliveapp_activity_vertical_margin"
android:paddingLeft="@dimen/oliveapp_activity_horizontal_margin"
android:paddingRight="@dimen/oliveapp_activity_horizontal_margin"
android:paddingTop="@dimen/oliveapp_activity_vertical_margin"
android:background="@color/colorDefaultBackground"
tools:context=".register.SampleChooseCameraActivity">
<LinearLayout
android:id="@+id/chooseImageTypeLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:layout_marginTop="50dp"
android:layout_marginLeft="30dp"
android:layout_marginRight="30dp">
<Button
android:id="@+id/IDcard"
android:layout_width="match_parent"
android:layout_height="46dp"
android:layout_marginBottom="30dp"
android:paddingLeft="50dp"
android:paddingRight="50dp"
android:text="@string/hintIDcard"
android:layout_gravity="center_horizontal"
android:textSize="16sp"
android:gravity="center_horizontal|center_vertical"
android:background="@drawable/oliveapp_button_background"
android:layout_marginTop="25dp"
android:textColor="#ffffff" />
<Button
android:id="@+id/Selfie"
android:layout_width="match_parent"
android:layout_height="46dp"
android:layout_marginBottom="30dp"
android:paddingLeft="50dp"
android:paddingRight="50dp"
android:text="@string/hintFrontCamera"
android:layout_gravity="center_horizontal"
android:textSize="16sp"
android:gravity="center_horizontal|center_vertical"
android:background="@drawable/oliveapp_button_background"
android:layout_marginTop="25dp"
android:textColor="#ffffff" />
<Button
android:id="@+id/IdcardFrontCapture"
android:layout_width="match_parent"
android:layout_height="46dp"
android:layout_marginBottom="30dp"
android:paddingLeft="50dp"
android:paddingRight="50dp"
android:text="@string/hintIdcardCapture"
android:layout_gravity="center_horizontal"
android:textSize="16sp"
android:gravity="center_horizontal|center_vertical"
android:background="@drawable/oliveapp_button_background"
android:layout_marginTop="25dp"
android:textColor="#ffffff" />
<Button
android:id="@+id/IdcardBackCapture"
android:layout_width="match_parent"
android:layout_height="46dp"
android:layout_marginBottom="30dp"
android:paddingLeft="50dp"
android:paddingRight="50dp"
android:text="@string/hintIdcardBackCapture"
android:layout_gravity="center_horizontal"
android:textSize="16sp"
android:gravity="center_horizontal|center_vertical"
android:background="@drawable/oliveapp_button_background"
android:layout_marginTop="25dp"
android:textColor="#ffffff" />
</LinearLayout>
</RelativeLayout>
<?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:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/oliveapp_activity_vertical_margin"
android:paddingLeft="@dimen/oliveapp_activity_horizontal_margin"
android:paddingRight="@dimen/oliveapp_activity_horizontal_margin"
android:paddingTop="@dimen/oliveapp_activity_vertical_margin"
android:background="@color/colorDefaultBackground"
tools:context=".register.SampleCameraResultActivity">
<ImageView
android:layout_width="300dp"
android:layout_height="300dp"
android:id="@+id/captureImageImageView"
android:layout_marginTop="10dp"
android:layout_centerHorizontal="true" />
<Button
android:layout_width="match_parent"
android:layout_height="46dp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:text="重新拍摄"
android:textColor="@color/colorWhite"
android:id="@+id/retakeButton"
android:layout_marginBottom="20dp"
android:layout_centerHorizontal="true"
android:background="@drawable/oliveapp_button_background"
android:layout_above="@+id/confirmButton" />
<Button
android:layout_width="match_parent"
android:layout_height="46dp"
android:layout_marginLeft="50dp"
android:layout_marginRight="50dp"
android:text="返回"
android:textColor="@color/colorWhite"
android:id="@+id/confirmButton"
android:background="@drawable/oliveapp_button_background"
android:layout_alignParentBottom="true"
android:layout_marginBottom="60dp"
android:layout_centerHorizontal="true" />
</RelativeLayout>
<?xml version="1.0" encoding="UTF-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:src="@drawable/arrow"
android:clickable="false"
android:focusable="false" />
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!-- 这里放上系统的id -->
<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:button="@drawable/selector_checkbox"
android:clickable="false"
android:focusable="false" />
\ No newline at end of file
<?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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".idcard_captor.view_controller.SampleIdcardCaptorMainActivity">
<RelativeLayout
android:id="@+id/oliveapp_face_captureLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:visibility="visible">
<RelativeLayout
android:id="@+id/oliveapp_face_previewLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true">
<view
android:id="@+id/oliveapp_face_cameraPreviewView"
class="com.oliveapp.camerasdk.ui.CameraRootView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerInParent="true"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/oliveapp_face_captureIDCardHintLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="visible">
<ImageView
android:id="@+id/oliveapp_face_idcardSkeletonImageView"
android:layout_width="252dp"
android:layout_height="400dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:src="@drawable/oliveapp_face_idcard_shade_skeleton_minimum3"
android:layout_centerInParent="true" />
<ImageView
android:id="@+id/oliveapp_face_scan_line"
android:layout_width="wrap_content"
android:layout_height="400dp"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:src="@drawable/oliveapp_scan_line"/>
<ImageView
android:id="@+id/oliveapp_face_shadowLeftImageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@+id/oliveapp_face_idcardSkeletonImageView"
android:layout_toStartOf="@+id/oliveapp_face_idcardSkeletonImageView"
android:scaleType="fitXY"
android:src="@drawable/oliveapp_face_black_shadow" />
<ImageView
android:id="@+id/oliveapp_face_shadowRightImageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="false"
android:layout_alignParentRight="true"
android:layout_toEndOf="@+id/oliveapp_face_idcardSkeletonImageView"
android:layout_toRightOf="@+id/oliveapp_face_idcardSkeletonImageView"
android:scaleType="fitXY"
android:src="@drawable/oliveapp_face_black_shadow" />
<ImageView
android:id="@+id/oliveapp_face_shadowTopImageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@+id/oliveapp_face_shadowRightImageView"
android:layout_toRightOf="@+id/oliveapp_face_shadowLeftImageView"
android:adjustViewBounds="false"
android:baselineAlignBottom="false"
android:scaleType="fitXY"
android:src="@drawable/oliveapp_face_black_shadow"
android:layout_above="@+id/oliveapp_face_idcardSkeletonImageView" />
<ImageView
android:id="@+id/oliveapp_face_shadowBottomImageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@+id/oliveapp_face_shadowRightImageView"
android:layout_toRightOf="@+id/oliveapp_face_shadowLeftImageView"
android:scaleType="fitXY"
android:src="@drawable/oliveapp_face_black_shadow"
android:layout_below="@+id/oliveapp_face_idcardSkeletonImageView" />
<com.oliveapp.libcommon.uicomponents.VerticalTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/oliveapp_face_hintTextView"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:text="@string/oliveapp_face_database_image_hint_front"
android:textColor="#ffffff"
android:layout_marginLeft="5dp" />
</RelativeLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/oliveapp_frame_rate_text"
android:text="FPS: "/>
</RelativeLayout>
<!--<RelativeLayout-->
<!--android:id="@+id/oliveapp_face_takePictureButtonLayout"-->
<!--android:layout_width="fill_parent"-->
<!--android:layout_height="64dp"-->
<!--android:layout_alignParentBottom="true"-->
<!--android:layout_alignParentLeft="true"-->
<!--android:layout_alignParentRight="true"-->
<!--android:layout_alignParentStart="true"-->
<!--android:layout_centerHorizontal="true"-->
<!--android:background="@drawable/oliveapp_face_black_shadow">-->
<ImageButton
android:id="@+id/oliveapp_face_takePictureButton"
style="?android:attr/borderlessButtonStyle"
android:layout_height="64dp"
android:layout_width="wrap_content"
android:clickable="true"
android:src="@drawable/oliveapp_camera_alt_white_48dp"
android:scaleType="fitCenter"
android:layout_alignParentBottom="true"
android:layout_centerInParent="true"
android:visibility="invisible"/>
<!--</RelativeLayout>-->
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/oliveapp_activity_horizontal_margin"
android:paddingRight="@dimen/oliveapp_activity_horizontal_margin"
android:paddingTop="@dimen/oliveapp_activity_vertical_margin"
android:paddingBottom="@dimen/oliveapp_activity_vertical_margin"
tools:context=".liveness.SampleUnusualResultActivity">
<ImageView
android:layout_width="400dp"
android:layout_height="200dp"
android:id="@+id/oliveappLivenessImageView"
android:scaleType="fitCenter"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="40dp" />
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/oliveapp_face_captureLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:visibility="visible">
<RelativeLayout
android:id="@+id/oliveapp_face_previewLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_centerInParent="true">
<view
android:id="@+id/oliveapp_face_cameraPreviewView"
class="com.oliveapp.camerasdk.ui.CameraRootView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/oliveapp_face_takePictureButtonLayout"
android:layout_width="fill_parent"
android:layout_height="64dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentStart="true"
android:layout_centerHorizontal="true"
android:background="@drawable/oliveapp_face_black_shadow">
<ImageButton
android:id="@+id/oliveapp_face_takePictureButton"
style="?android:attr/borderlessButtonStyle"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:clickable="true"
android:src="@drawable/oliveapp_camera_alt_white_48dp"
android:scaleType="fitCenter"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_centerInParent="true" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/oliveapp_face_captureIDCardHintLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="@+id/oliveapp_face_takePictureButtonLayout"
android:visibility="visible">
<ImageView
android:id="@+id/oliveapp_face_idcardSkeletonImageView"
android:layout_width="280dp"
android:layout_height="448dp"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
android:src="@drawable/oliveapp_face_idcard_shade_skeleton_minimum2"
android:layout_centerInParent="true" />
<ImageView
android:id="@+id/oliveapp_face_shadowLeftImageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@+id/oliveapp_face_idcardSkeletonImageView"
android:layout_toStartOf="@+id/oliveapp_face_idcardSkeletonImageView"
android:scaleType="fitXY"
android:src="@drawable/oliveapp_face_black_shadow" />
<ImageView
android:id="@+id/oliveapp_face_shadowRightImageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentLeft="false"
android:layout_alignParentRight="true"
android:layout_toEndOf="@+id/oliveapp_face_idcardSkeletonImageView"
android:layout_toRightOf="@+id/oliveapp_face_idcardSkeletonImageView"
android:scaleType="fitXY"
android:src="@drawable/oliveapp_face_black_shadow" />
<ImageView
android:id="@+id/oliveapp_face_shadowTopImageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_toLeftOf="@+id/oliveapp_face_shadowRightImageView"
android:layout_toRightOf="@+id/oliveapp_face_shadowLeftImageView"
android:adjustViewBounds="false"
android:baselineAlignBottom="false"
android:scaleType="fitXY"
android:src="@drawable/oliveapp_face_black_shadow"
android:layout_above="@+id/oliveapp_face_idcardSkeletonImageView" />
<ImageView
android:id="@+id/oliveapp_face_shadowBottomImageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@+id/oliveapp_face_shadowRightImageView"
android:layout_toRightOf="@+id/oliveapp_face_shadowLeftImageView"
android:scaleType="fitXY"
android:src="@drawable/oliveapp_face_black_shadow"
android:layout_below="@+id/oliveapp_face_idcardSkeletonImageView" />
<com.oliveapp.libcommon.uicomponents.VerticalTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/oliveapp_face_hintTextView"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:text="@string/oliveapp_face_database_image_hint_front"
android:textColor="#ffffff"
android:layout_marginLeft="5dp" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/oliveapp_face_captureLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:visibility="visible">
<RelativeLayout
android:id="@+id/oliveapp_face_previewLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_centerInParent="true">
<view
android:id="@+id/oliveapp_face_cameraPreviewView"
class="com.oliveapp.camerasdk.ui.CameraRootView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" />
<ImageView
android:id="@+id/oliveapp_face_previewCapturedImageView"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:scaleType="centerCrop" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/oliveapp_face_takePictureButtonLayout"
android:layout_width="fill_parent"
android:layout_height="64dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentStart="true"
android:layout_centerHorizontal="true"
android:background="@drawable/oliveapp_face_black_shadow">
<ImageButton
android:id="@+id/oliveapp_face_takePictureButton"
style="?android:attr/borderlessButtonStyle"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:clickable="true"
android:src="@drawable/oliveapp_camera_alt_white_48dp"
android:scaleType="fitCenter"
android:layout_alignParentBottom="true"
android:layout_alignParentTop="true"
android:layout_centerInParent="true" />
</RelativeLayout>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_above="@+id/oliveapp_face_takePictureButtonLayout"
android:id="@+id/oliveapp_face_captureSemiIDCardHintLayout">
<RelativeLayout
android:layout_width="280dp"
android:layout_height="280dp"
android:id="@+id/oliveapp_face_faceSkeletonImageLayout"
android:layout_centerHorizontal="true"
android:layout_marginTop="90dp">
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/oliveapp_face_faceSkeletonImageView"
android:src="@drawable/oliveapp_face_skeleton_minimum2"
android:scaleType="fitCenter"
android:layout_centerHorizontal="true"
android:adjustViewBounds="true" />
</RelativeLayout>
<ImageView
android:layout_width="fill_parent"
android:layout_height="90dp"
android:id="@+id/oliveapp_face_faceShadeTopImageView"
android:src="@drawable/oliveapp_face_black_shadow"
android:layout_alignParentTop="true"
android:scaleType="fitXY" />
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/oliveapp_face_faceShadeBottomImageView"
android:src="@drawable/oliveapp_face_black_shadow"
android:layout_alignParentBottom="true"
android:scaleType="fitXY"
android:layout_below="@+id/oliveapp_face_faceSkeletonImageLayout" />
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/oliveapp_face_faceShadeLeftImageView"
android:src="@drawable/oliveapp_face_black_shadow"
android:layout_toLeftOf="@+id/oliveapp_face_faceSkeletonImageLayout"
android:layout_toStartOf="@+id/oliveapp_face_faceSkeletonImageLayout"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:scaleType="fitXY"
android:layout_below="@+id/oliveapp_face_faceShadeTopImageView"
android:layout_above="@+id/oliveapp_face_faceShadeBottomImageView" />
<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/oliveapp_face_faceShadeRightImageView"
android:src="@drawable/oliveapp_face_black_shadow"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_toRightOf="@+id/oliveapp_face_faceSkeletonImageLayout"
android:layout_toEndOf="@+id/oliveapp_face_faceSkeletonImageLayout"
android:scaleType="fitXY"
android:layout_below="@+id/oliveapp_face_faceShadeTopImageView"
android:layout_above="@+id/oliveapp_face_faceShadeBottomImageView" />
</RelativeLayout>
</RelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.oliveapp.liveness.sample.uicomponents.FixedAspectLayout
android:id="@+id/oliveapp_cameraPreviewLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:oliveapp_fixMode="fixWidth">
<view
android:id="@+id/oliveapp_cameraPreviewView"
class="com.oliveapp.camerasdk.ui.CameraRootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginTop="0dp" />
</com.oliveapp.liveness.sample.uicomponents.FixedAspectLayout>
<android.support.percent.PercentRelativeLayout
android:id="@+id/oliveapp_detected_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--滤镜-->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:scaleType="centerCrop"
android:src="@mipmap/oliveapp_background_filter_landscape_tablet" />
<!--人脸框-->
<ImageView
android:id="@+id/oliveapp_start_frame"
android:layout_centerHorizontal="true"
android:src="@mipmap/oliveapp_detect_frame"
app:layout_heightPercent="60%"
app:layout_marginTopPercent="20%"
app:layout_widthPercent="40%" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_marginTopPercent="3%"
app:layout_marginLeftPercent="3%"
android:textSize="20sp"
android:textColor="#ffffff"
android:id="@+id/oliveapp_frame_rate_text"/>
<!--关闭按钮-->
<ImageButton
android:id="@+id/oliveapp_close_image_button"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
app:layout_marginRightPercent="7%"
app:layout_marginTopPercent="7%"
app:layout_aspectRatio="75%"
app:layout_heightPercent="5%"
android:background="@mipmap/oliveapp_close_icon"/>
<!--提示文字-->
<android.support.percent.PercentRelativeLayout
android:layout_centerHorizontal="true"
app:layout_heightPercent="10%"
app:layout_marginRightPercent="20%"
app:layout_marginTopPercent="24.6%"
app:layout_widthPercent="60%">
<TextView
android:id="@+id/oliveapp_detected_hint_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/oliveapp_step_hint_focus"
android:textColor="#FFFF00"
android:textSize="40sp"
android:textStyle="bold"
app:layout_marginLeftPercent="2%"
app:layout_marginRightPercent="2%" />
<ImageView
android:id="@+id/oliveapp_detected_hint_left_border"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@id/oliveapp_detected_hint_text"
android:src="@mipmap/oliveapp_detect_hint_left_corner"
app:layout_heightPercent="20%"
app:layout_widthPercent="2%" />
<ImageView
android:id="@+id/oliveapp_detected_hint_right_border"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/oliveapp_detected_hint_text"
android:src="@mipmap/oliveapp_detect_hint_right_corner"
app:layout_heightPercent="20%"
app:layout_widthPercent="2%" />
</android.support.percent.PercentRelativeLayout>
<!--倒计时-->
<TextView
android:id="@+id/oliveapp_count_time_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFF"
android:textSize="50sp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="20dp"
/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/oliveapp_activity_vertical_margin"
android:paddingLeft="@dimen/oliveapp_activity_horizontal_margin"
android:paddingRight="@dimen/oliveapp_activity_horizontal_margin"
android:paddingTop="@dimen/oliveapp_activity_vertical_margin"
tools:context=".liveness.view_controller.LivenessDetectionMainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.oliveapp.liveness.sample.uicomponents.FixedAspectLayout
android:id="@+id/oliveapp_cameraPreviewLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:oliveapp_fixMode="fixWidth">
<view
android:id="@+id/oliveapp_cameraPreviewView"
class="com.oliveapp.camerasdk.ui.CameraRootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginTop="0dp" />
</com.oliveapp.liveness.sample.uicomponents.FixedAspectLayout>
<android.support.percent.PercentRelativeLayout
android:id="@+id/oliveapp_detected_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--滤镜-->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/oliveapp_background_filter_portrait_phone" />
<!--人脸框-->
<ImageView
android:id="@+id/oliveapp_start_frame"
android:layout_centerHorizontal="true"
android:background="@mipmap/oliveapp_detect_frame"
android:scaleType="centerCrop"
app:layout_heightPercent="41.3%"
app:layout_marginLeftPercent="13.2%"
app:layout_marginTopPercent="27.4%"
app:layout_widthPercent="73.5%" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_marginTopPercent="3%"
app:layout_marginLeftPercent="3%"
android:textSize="20sp"
android:textColor="#ffffff"
android:id="@+id/oliveapp_frame_rate_text"/>
<!--关闭按钮-->
<ImageButton
android:id="@+id/oliveapp_close_image_button"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="@mipmap/oliveapp_close_icon"
app:layout_heightPercent="4%"
app:layout_marginRightPercent="6.6%"
app:layout_marginTopPercent="6.8%"
app:layout_aspectRatio="100%"/>
<!--提示文字-->
<android.support.percent.PercentRelativeLayout
android:layout_centerHorizontal="true"
app:layout_heightPercent="5.2%"
app:layout_marginTopPercent="19.4%"
app:layout_widthPercent="100%">
<TextView
android:id="@+id/oliveapp_detected_hint_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textColor="#FFFF00"
android:textSize="24sp"
android:text="@string/oliveapp_step_hint_focus"
app:layout_marginLeftPercent="2%"
app:layout_marginRightPercent="2%"/>
<ImageView
android:id="@+id/oliveapp_detected_hint_left_border"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@id/oliveapp_detected_hint_text"
android:src="@mipmap/oliveapp_detect_hint_left_corner"
app:layout_heightPercent="18%"
app:layout_widthPercent="4%"/>
<ImageView
android:id="@+id/oliveapp_detected_hint_right_border"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/oliveapp_detected_hint_text"
android:src="@mipmap/oliveapp_detect_hint_right_corner"
app:layout_heightPercent="18%"
app:layout_widthPercent="4%" />
</android.support.percent.PercentRelativeLayout>
<!--倒计时-->
<TextView
android:id="@+id/oliveapp_count_time_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFF"
android:textSize="50sp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="20dp"
/>
</android.support.percent.PercentRelativeLayout>
</FrameLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.oliveapp.liveness.sample.uicomponents.FixedAspectLayout
android:id="@+id/oliveapp_cameraPreviewLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:oliveapp_fixMode="fixWidth">
<view
android:id="@+id/oliveapp_cameraPreviewView"
class="com.oliveapp.camerasdk.ui.CameraRootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="0dp"
android:layout_marginLeft="0dp"
android:layout_marginRight="0dp"
android:layout_marginTop="0dp"/>
</com.oliveapp.liveness.sample.uicomponents.FixedAspectLayout>
<android.support.percent.PercentRelativeLayout
android:id="@+id/oliveapp_detected_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--滤镜-->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerHorizontal="true"
android:scaleType="centerCrop"
android:src="@mipmap/oliveapp_background_filter_portrait_phone" />
<!--人脸框-->
<ImageView
android:id="@+id/oliveapp_start_frame"
android:layout_centerHorizontal="true"
android:src="@mipmap/oliveapp_detect_frame"
app:layout_marginTopPercent="25%"
app:layout_heightPercent="42.5%"
app:layout_widthPercent="73.5%"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_marginTopPercent="3%"
app:layout_marginLeftPercent="3%"
android:textSize="20sp"
android:textColor="#ffffff"
android:id="@+id/oliveapp_frame_rate_text"/>
<!--关闭按钮-->
<ImageButton
android:id="@+id/oliveapp_close_image_button"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="@mipmap/oliveapp_close_icon"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_heightPercent="4%"
app:layout_aspectRatio="100%"
app:layout_marginRightPercent="6.6%"
app:layout_marginTopPercent="6.8%"/>
<!--提示文字-->
<android.support.percent.PercentRelativeLayout
android:id="@+id/oliveapp_detected_hint_text_layout"
android:layout_centerHorizontal="true"
app:layout_heightPercent="5.2%"
app:layout_marginTopPercent="12%"
app:layout_widthPercent="100%">
<TextView
android:id="@+id/oliveapp_detected_hint_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="请正对屏幕"
android:textColor="#FFFF00"
android:textSize="24sp" />
<ImageView
android:id="@+id/oliveapp_detected_hint_left_border"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@id/oliveapp_detected_hint_text"
android:src="@mipmap/oliveapp_detect_hint_left_corner"
app:layout_heightPercent="18%"
app:layout_widthPercent="4%" />
<ImageView
android:id="@+id/oliveapp_detected_hint_right_border"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/oliveapp_detected_hint_text"
android:src="@mipmap/oliveapp_detect_hint_right_corner"
app:layout_heightPercent="18%"
app:layout_widthPercent="4%" />
</android.support.percent.PercentRelativeLayout>
<!--倒计时-->
<TextView
android:id="@+id/oliveapp_count_time_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFF"
android:textSize="50sp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="20dp"
/>
</android.support.percent.PercentRelativeLayout>
</FrameLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/oliveapp_liveness_finish_bg_landscape_tablet">
<!--检测结果-->
<ImageView
android:id="@+id/oliveapp_liveness_result_image"
android:layout_centerHorizontal="true"
android:src="@mipmap/oliveapp_liveness_finish_fail"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_marginTopPercent="13.5%"
app:layout_widthPercent="36%"
app:layout_aspectRatio="462%"/>
<TextView
android:id="@+id/oliveappResultTextView"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal"
app:layout_widthPercent="80%"
app:layout_heightPercent="20%"
app:layout_marginTopPercent="41.6%"
android:textSize="40sp"
android:textColor="#FFFFFF"/>
<Button
android:id="@+id/oliveapp_liveness_result_retry"
android:layout_alignParentBottom="true"
android:background="@drawable/oliveapp_liveness_finish_retry_tablet_selector"
app:layout_marginBottomPercent="10.8%"
app:layout_marginLeftPercent="15%"
app:layout_widthPercent="31%"
app:layout_aspectRatio="300%"/>
<Button
android:id="@+id/oliveapp_liveness_result_return"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="@drawable/oliveapp_liveness_finish_return_tablet_selector"
app:layout_marginBottomPercent="10.8%"
app:layout_marginRightPercent="15%"
app:layout_widthPercent="31%"
app:layout_aspectRatio="300%"/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingLeft="@dimen/oliveapp_activity_horizontal_margin"
android:paddingRight="@dimen/oliveapp_activity_horizontal_margin"
android:paddingTop="@dimen/oliveapp_activity_vertical_margin"
android:paddingBottom="@dimen/oliveapp_activity_vertical_margin"
android:background="@mipmap/oliveapp_liveness_resultpage_bg"
tools:context="SampleUnusualResultActivity">
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--检测结果-->
<ImageView
android:id="@+id/oliveapp_liveness_result_image"
android:layout_centerHorizontal="true"
android:background="@mipmap/oliveapp_liveness_finish_fail"
app:layout_marginTopPercent="33.6%"
app:layout_widthPercent="49.1%"
app:layout_aspectRatio="462%"/>
<TextView
android:id="@+id/oliveappResultTextView"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal"
app:layout_widthPercent="80%"
app:layout_heightPercent="20%"
app:layout_marginTopPercent="41.6%"
android:textSize="30sp"
android:textColor="#FFFFFF"/>
<Button
android:id="@+id/oliveapp_liveness_result_retry"
android:layout_alignParentBottom="true"
android:background="@drawable/oliveapp_liveness_finish_retry"
app:layout_marginBottomPercent="8%"
app:layout_marginLeftPercent="6.1%"
app:layout_widthPercent="41.7%"
app:layout_aspectRatio="295%"/>
<Button
android:id="@+id/oliveapp_liveness_result_return"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="@drawable/oliveapp_liveness_finish_return_selector"
app:layout_marginBottomPercent="8%"
app:layout_marginRightPercent="6.1%"
app:layout_widthPercent="41.7%"
app:layout_aspectRatio="295%"/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/oliveapp_liveness_finish_bg_landscape_tablet">
<!--检测结果-->
<ImageView
android:id="@+id/oliveapp_liveness_result_image"
android:layout_centerHorizontal="true"
android:background="@mipmap/oliveapp_liveness_finish_fail"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_marginTopPercent="30%"
app:layout_widthPercent="49.1%"
app:layout_aspectRatio='462%'/>
<TextView
android:id="@+id/oliveappResultTextView"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal"
app:layout_widthPercent="80%"
app:layout_heightPercent="20%"
app:layout_marginTopPercent="41.6%"
android:textSize="40sp"
android:textColor="#FFFFFF"/>
<Button
android:id="@+id/oliveapp_liveness_result_retry"
android:layout_alignParentBottom="true"
android:background="@drawable/oliveapp_liveness_finish_retry_tablet_selector"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_marginBottomPercent="10.8%"
app:layout_marginLeftPercent="10%"
app:layout_widthPercent="35%"
app:layout_aspectRatio="328%"/>
<Button
android:id="@+id/oliveapp_liveness_result_return"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="@drawable/oliveapp_liveness_finish_return_tablet_selector"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_marginBottomPercent="10.8%"
app:layout_marginRightPercent="10%"
app:layout_widthPercent="35%"
app:layout_aspectRatio="328%"/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/oliveapp_liveness_finish_bg_landscape_tablet">
<!--检测结果-->
<ImageView
android:id="@+id/oliveapp_liveness_result_image"
android:layout_centerHorizontal="true"
android:src="@mipmap/oliveapp_liveness_finish_fail"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_marginRightPercent="25.5%"
app:layout_marginTopPercent="13.5%"
app:layout_widthPercent="36%"
app:layout_aspectRatio="462%"/>
<!--将下面列表使用listview表示-->
<ListView
android:id="@+id/oliveapp_liveness_saas_list"
android:layout_alignParentLeft="true"
app:layout_widthPercent="40%"
app:layout_heightPercent="40%"
app:layout_marginTopPercent="33.8%"
app:layout_marginLeftPercent="8.3%"
android:isScrollContainer="false"
android:divider="@android:color/transparent"
android:listSelector="@android:color/transparent"/>
<ImageView
android:layout_centerHorizontal="true"
app:layout_heightPercent="40%"
app:layout_widthPercent="2%"
app:layout_marginTopPercent="33%"
android:src="@mipmap/oliveapp_divider_tablet"/>
<android.support.percent.PercentRelativeLayout
app:layout_widthPercent="40%"
app:layout_heightPercent="40%"
app:layout_marginTopPercent="33%"
app:layout_marginRightPercent="8.2%"
android:layout_alignParentRight="true"
android:background="@mipmap/oliveapp_liveness_result_border">
<!--两张人脸-->
<!--第一张-->
<ImageView
android:id="@+id/oliveapp_liveness_result_close"
app:layout_widthPercent="45%"
app:layout_heightPercent="90%"
app:layout_marginTopPercent="5%"
app:layout_marginLeftPercent="2.5%"/>
<ImageView
app:layout_widthPercent="40%"
app:layout_heightPercent="80%"
app:layout_marginTopPercent="10%"
app:layout_marginLeftPercent="5%"
android:src="@mipmap/oliveapp_liveness_result_face_border"/>
<!--第二张-->
<ImageView
android:id="@+id/oliveapp_liveness_result_open"
app:layout_widthPercent="45%"
app:layout_heightPercent="90%"
app:layout_marginTopPercent="5%"
app:layout_marginRightPercent="2.5%"
android:layout_alignParentRight="true"/>
<ImageView
app:layout_widthPercent="40%"
app:layout_heightPercent="80%"
app:layout_marginTopPercent="10%"
app:layout_marginRightPercent="5%"
android:layout_alignParentRight="true"
android:src="@mipmap/oliveapp_liveness_result_face_border"/>
</android.support.percent.PercentRelativeLayout>
<Button
android:id="@+id/oliveapp_liveness_saas_result_retry"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="@drawable/oliveapp_liveness_finish_retry_tablet_selector"
app:layout_marginBottomPercent="9%"
app:layout_marginRightPercent="28%"
app:layout_widthPercent="18%"
app:layout_aspectRatio="200%" />
<Button
android:id="@+id/oliveapp_liveness_saas_result_return"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="@drawable/oliveapp_liveness_finish_return_tablet_selector"
app:layout_marginBottomPercent="9%"
app:layout_marginRightPercent="8.3%"
app:layout_widthPercent="18%"
app:layout_aspectRatio="200%"/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_sample_saa_sresult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/oliveapp_liveness_resultpage_bg"
tools:context="com.oliveapp.liveness.sample.SampleSaaSResultActivity">
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--检测结果-->
<ImageView
android:id="@+id/oliveapp_liveness_result_image"
android:layout_centerHorizontal="true"
android:background="@mipmap/oliveapp_liveness_finish_fail"
app:layout_marginRightPercent="25.5%"
app:layout_marginTopPercent="9.7%"
app:layout_widthPercent="49.1%"
app:layout_aspectRatio="462%"/>
<ImageView
app:layout_widthPercent="87.8%"
app:layout_heightPercent="24.6%"
app:layout_marginTopPercent="20.4%"
app:layout_marginRightPercent="5.1%"
android:layout_centerHorizontal="true"
android:background="@mipmap/oliveapp_liveness_result_border"/>
<!--两张人脸-->
<!--第一张-->
<ImageView
android:id="@+id/oliveapp_liveness_result_close"
app:layout_widthPercent="35.12%"
app:layout_heightPercent="19.68%"
app:layout_marginTopPercent="22.86%"
app:layout_marginLeftPercent="10.49%"/>
<ImageView
app:layout_widthPercent="28.9%"
app:layout_heightPercent="16.3%"
app:layout_marginTopPercent="24.6%"
app:layout_marginLeftPercent="13.5%"
android:src="@mipmap/oliveapp_liveness_result_face_border"/>
<!--第二张-->
<ImageView
android:id="@+id/oliveapp_liveness_result_open"
app:layout_widthPercent="35.12%"
app:layout_heightPercent="19.68%"
app:layout_marginTopPercent="22.86%"
app:layout_marginRightPercent="10.49%"
android:layout_alignParentRight="true"/>
<ImageView
app:layout_widthPercent="28.9%"
app:layout_heightPercent="16.3%"
app:layout_marginTopPercent="24.6%"
app:layout_marginLeftPercent="57.6%"
android:src="@mipmap/oliveapp_liveness_result_face_border"/>
<!--将下面列表使用listview表示-->
<ListView
android:id="@+id/oliveapp_liveness_saas_list"
android:layout_alignParentBottom="true"
app:layout_widthPercent="82.7%"
app:layout_heightPercent="25.4%"
app:layout_marginBottomPercent="25.3%"
app:layout_marginLeftPercent="8.6%"
android:isScrollContainer="false"
android:divider="@android:color/transparent"
android:listSelector="@android:color/transparent"/>
<Button
android:id="@+id/oliveapp_liveness_saas_result_retry"
android:layout_alignParentBottom="true"
android:background="@drawable/oliveapp_liveness_finish_retry"
app:layout_marginBottomPercent="8%"
app:layout_marginLeftPercent="6.1%"
app:layout_widthPercent="41.7%"
app:layout_aspectRatio="295%"/>
<Button
android:id="@+id/oliveapp_liveness_saas_result_return"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="@drawable/oliveapp_liveness_finish_return_selector"
app:layout_marginBottomPercent="8%"
app:layout_marginRightPercent="6.1%"
app:layout_widthPercent="41.7%"
app:layout_aspectRatio="295%"/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/oliveapp_liveness_finish_bg_landscape_tablet">
<!--检测结果-->
<ImageView
android:id="@+id/oliveapp_liveness_result_image"
android:layout_centerHorizontal="true"
android:src="@mipmap/oliveapp_liveness_finish_fail"
app:layout_marginRightPercent="25.5%"
app:layout_marginTopPercent="9.7%"
app:layout_widthPercent="49.1%"
app:layout_heightPercent="7%"/>
<ImageView
app:layout_widthPercent="87.8%"
app:layout_heightPercent="24.6%"
app:layout_marginTopPercent="20.4%"
app:layout_marginRightPercent="5.1%"
android:layout_centerHorizontal="true"
android:background="@mipmap/oliveapp_liveness_result_border"/>
<!--两张人脸-->
<!--第一张-->
<ImageView
android:id="@+id/oliveapp_liveness_result_close"
app:layout_widthPercent="35.12%"
app:layout_heightPercent="19.68%"
app:layout_marginTopPercent="22.86%"
app:layout_marginLeftPercent="10.49%"/>
<ImageView
app:layout_widthPercent="28.9%"
app:layout_heightPercent="16.3%"
app:layout_marginTopPercent="24.6%"
app:layout_marginLeftPercent="13.5%"
android:src="@mipmap/oliveapp_liveness_result_face_border"/>
<!--第二张-->
<ImageView
android:id="@+id/oliveapp_liveness_result_open"
app:layout_widthPercent="35.12%"
app:layout_heightPercent="19.68%"
app:layout_marginTopPercent="22.86%"
app:layout_marginRightPercent="10.49%"
android:layout_alignParentRight="true"/>
<ImageView
app:layout_widthPercent="28.9%"
app:layout_heightPercent="16.3%"
app:layout_marginTopPercent="24.6%"
app:layout_marginLeftPercent="57.6%"
android:src="@mipmap/oliveapp_liveness_result_face_border"/>
<!--将下面列表使用listview表示-->
<ListView
android:id="@+id/oliveapp_liveness_saas_list"
android:layout_alignParentBottom="true"
app:layout_widthPercent="82.7%"
app:layout_heightPercent="25.4%"
app:layout_marginBottomPercent="25.3%"
app:layout_marginLeftPercent="8.6%"
android:isScrollContainer="false"
android:divider="@android:color/transparent"
android:listSelector="@android:color/transparent"/>
<Button
android:id="@+id/oliveapp_liveness_saas_result_retry"
android:layout_alignParentBottom="true"
android:background="@drawable/oliveapp_liveness_finish_retry_tablet_selector"
app:layout_marginBottomPercent="8%"
app:layout_marginLeftPercent="6.1%"
app:layout_widthPercent="41.7%"
app:layout_aspectRatio="326%"/>
<Button
android:id="@+id/oliveapp_liveness_saas_result_return"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:background="@drawable/oliveapp_liveness_finish_return_tablet_selector"
app:layout_marginBottomPercent="8%"
app:layout_marginRightPercent="6.1%"
app:layout_widthPercent="41.7%"
app:layout_aspectRatio="326%"/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.percent.PercentRelativeLayout
android:id="@+id/oliveapp_liveness_result_list_layout"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/oliveapp_liveness_result_item"
android:gravity="center_vertical|left"
app:layout_widthPercent="70%"
app:layout_heightPercent="100%"
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:textColor="#FFFFFF"
android:text="大礼包照片是否同一个人"/>
<ImageView
android:id="@+id/oliveapp_liveness_result_yesorno"
app:layout_widthPercent="10%"
app:layout_heightPercent="40%"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:src="@mipmap/oliveapp_liveness_result_right"/>
<TextView
android:id="@+id/oliveapp_liveness_result_detail"
app:layout_widthPercent="20%"
app:layout_heightPercent="50%"
app:layout_marginRightPercent="3%"
android:gravity="end"
android:layout_centerVertical="true"
android:layout_toLeftOf="@id/oliveapp_liveness_result_yesorno"
android:textColor="#6DE3E7"
android:text="0.0000000"/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/oliveapp_liveness_finish_bg_landscape_tablet">
<!--检测结果-->
<ImageView
android:id="@+id/oliveapp_liveness_result_image"
android:layout_centerHorizontal="true"
android:src="@mipmap/oliveapp_liveness_finish_pass_tablet"
android:layout_height="0dp"
android:layout_width="0dp"
app:layout_marginTopPercent="13.5%"
app:layout_widthPercent="36%"
app:layout_aspectRatio="462%"/>
<!--将下面列表使用listview表示-->
<ListView
android:id="@+id/oliveapp_liveness_saas_list"
android:layout_alignParentLeft="true"
app:layout_widthPercent="40%"
app:layout_heightPercent="40%"
app:layout_marginTopPercent="33.8%"
app:layout_marginLeftPercent="8.3%"
android:isScrollContainer="false"
android:divider="@android:color/transparent"
android:listSelector="@android:color/transparent"/>
<ImageView
android:layout_centerHorizontal="true"
app:layout_heightPercent="40%"
app:layout_widthPercent="2%"
app:layout_marginTopPercent="33%"
android:src="@mipmap/oliveapp_divider_tablet"/>
<android.support.percent.PercentRelativeLayout
app:layout_widthPercent="40%"
app:layout_heightPercent="40%"
app:layout_marginTopPercent="33%"
app:layout_marginRightPercent="8.2%"
android:layout_alignParentRight="true"
android:background="@mipmap/oliveapp_liveness_result_border">
<!--两张人脸-->
<!--第一张-->
<ImageView
android:id="@+id/oliveapp_liveness_result_close"
app:layout_widthPercent="45%"
app:layout_heightPercent="90%"
app:layout_marginTopPercent="5%"
app:layout_marginLeftPercent="2.5%"/>
<ImageView
app:layout_widthPercent="40%"
app:layout_heightPercent="80%"
app:layout_marginTopPercent="10%"
app:layout_marginLeftPercent="5%"
android:src="@mipmap/oliveapp_liveness_result_face_border"/>
<!--第二张-->
<ImageView
android:id="@+id/oliveapp_liveness_result_open"
app:layout_widthPercent="45%"
app:layout_heightPercent="90%"
app:layout_marginTopPercent="5%"
app:layout_marginRightPercent="2.5%"
android:layout_alignParentRight="true"/>
<ImageView
app:layout_widthPercent="40%"
app:layout_heightPercent="80%"
app:layout_marginTopPercent="10%"
app:layout_marginRightPercent="5%"
android:layout_alignParentRight="true"
android:src="@mipmap/oliveapp_liveness_result_face_border"/>
</android.support.percent.PercentRelativeLayout>
<Button
android:id="@+id/oliveapp_liveness_saas_result_finish"
android:layout_alignParentRight="true"
app:layout_marginTopPercent="82%"
app:layout_marginRightPercent="8.3%"
app:layout_widthPercent="18%"
app:layout_aspectRatio="200%"
android:background="@drawable/oliveapp_liveness_finish_button_tablet_selector"/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_sample_saa_sresult"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/oliveapp_liveness_resultpage_bg"
tools:context="com.oliveapp.liveness.sample.liveness.SampleSaaSResultActivity">
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--检测结果-->
<ImageView
android:id="@+id/oliveapp_liveness_result_image"
android:layout_centerHorizontal="true"
android:background="@mipmap/oliveapp_liveness_finish_pass"
app:layout_marginTopPercent="9.7%"
app:layout_widthPercent="49.1%"
app:layout_aspectRatio="462%"/>
<ImageView
app:layout_widthPercent="87.8%"
app:layout_heightPercent="24.6%"
app:layout_marginTopPercent="20.4%"
app:layout_marginLeftPercent="6.1%"
android:layout_centerHorizontal="true"
android:background="@mipmap/oliveapp_liveness_result_border"/>
<!--两张人脸-->
<!--第一张-->
<ImageView
android:id="@+id/oliveapp_liveness_result_close"
app:layout_widthPercent="35.12%"
app:layout_heightPercent="19.68%"
app:layout_marginTopPercent="22.86%"
app:layout_marginLeftPercent="10.49%"/>
<ImageView
app:layout_widthPercent="28.9%"
app:layout_heightPercent="16.3%"
app:layout_marginTopPercent="24.6%"
app:layout_marginLeftPercent="13.5%"
android:src="@mipmap/oliveapp_liveness_result_face_border"/>
<!--第二张-->
<ImageView
android:id="@+id/oliveapp_liveness_result_open"
app:layout_widthPercent="35.12%"
app:layout_heightPercent="19.68%"
app:layout_marginTopPercent="22.86%"
app:layout_marginRightPercent="10.49%"
android:layout_alignParentRight="true"/>
<ImageView
app:layout_widthPercent="28.9%"
app:layout_heightPercent="16.3%"
app:layout_marginTopPercent="24.6%"
app:layout_marginLeftPercent="57.6%"
android:src="@mipmap/oliveapp_liveness_result_face_border"/>
<!--将下面列表使用listview表示-->
<ListView
android:id="@+id/oliveapp_liveness_saas_list"
android:layout_alignParentBottom="true"
app:layout_widthPercent="82.7%"
app:layout_heightPercent="25.4%"
app:layout_marginBottomPercent="25.3%"
app:layout_marginLeftPercent="8.6%"
android:isScrollContainer="false"
android:divider="@android:color/transparent"
android:listSelector="@android:color/transparent"/>
<Button
android:id="@+id/oliveapp_liveness_saas_result_finish"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/oliveapp_liveness_finish_button_selector"
app:layout_aspectRatio="618%"
app:layout_marginBottomPercent="8%"
app:layout_widthPercent="87.8%" />
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/oliveapp_liveness_finish_bg_landscape_tablet">
<!--检测结果-->
<ImageView
android:id="@+id/oliveapp_liveness_result_image"
android:layout_centerHorizontal="true"
android:background="@mipmap/oliveapp_liveness_finish_pass"
app:layout_marginRightPercent="25.5%"
app:layout_marginTopPercent="9.7%"
app:layout_widthPercent="50%"
app:layout_aspectRatio="462%"/>
<ImageView
app:layout_widthPercent="87.8%"
app:layout_heightPercent="24.6%"
app:layout_marginTopPercent="20.4%"
app:layout_marginLeftPercent="6.1%"
android:layout_centerHorizontal="true"
android:background="@mipmap/oliveapp_liveness_result_border"/>
<!--两张人脸-->
<!--第一张-->
<ImageView
android:id="@+id/oliveapp_liveness_result_close"
app:layout_widthPercent="35.12%"
app:layout_heightPercent="19.68%"
app:layout_marginTopPercent="22.86%"
app:layout_marginLeftPercent="10.49%"/>
<ImageView
app:layout_widthPercent="28.9%"
app:layout_heightPercent="16.3%"
app:layout_marginTopPercent="24.6%"
app:layout_marginLeftPercent="13.5%"
android:src="@mipmap/oliveapp_liveness_result_face_border"/>
<!--第二张-->
<ImageView
android:id="@+id/oliveapp_liveness_result_open"
app:layout_widthPercent="35.12%"
app:layout_heightPercent="19.68%"
app:layout_marginTopPercent="22.86%"
app:layout_marginRightPercent="10.49%"
android:layout_alignParentRight="true"/>
<ImageView
app:layout_widthPercent="28.9%"
app:layout_heightPercent="16.3%"
app:layout_marginTopPercent="24.6%"
app:layout_marginLeftPercent="57.6%"
android:src="@mipmap/oliveapp_liveness_result_face_border"/>
<!--将下面列表使用listview表示-->
<ListView
android:id="@+id/oliveapp_liveness_saas_list"
android:layout_alignParentBottom="true"
app:layout_widthPercent="82.7%"
app:layout_heightPercent="25.4%"
app:layout_marginBottomPercent="25.3%"
app:layout_marginLeftPercent="8.6%"
android:isScrollContainer="false"
android:divider="@android:color/transparent"
android:listSelector="@android:color/transparent"/>
<Button
android:id="@+id/oliveapp_liveness_saas_result_finish"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/oliveapp_liveness_finish_button_selector"
app:layout_marginBottomPercent="8%"
app:layout_widthPercent="87.8%"
app:layout_aspectRatio="618%"/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/oliveapp_start_button_layout">
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@mipmap/oliveapp_homepage_bg_landscape_tablet">
<!--关闭按钮-->
<ImageButton
android:id="@+id/oliveappCloseLivenessButton"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="@mipmap/oliveapp_close_icon"
app:layout_aspectRatio="100%"
app:layout_heightPercent="6%"
app:layout_marginRightPercent="6.3%"
app:layout_marginTopPercent="21%"/>
<Button
android:id="@+id/oliveappStartLivenessButton"
android:background="@drawable/oliveapp_start_button_tablet_selector"
android:layout_alignParentRight="true"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_marginRightPercent="16%"
app:layout_marginTopPercent="60%"
app:layout_widthPercent="20%"
app:layout_aspectRatio="256%"/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/oliveapp_activity_vertical_margin"
android:paddingLeft="@dimen/oliveapp_activity_horizontal_margin"
android:paddingRight="@dimen/oliveapp_activity_horizontal_margin"
android:paddingTop="@dimen/oliveapp_activity_vertical_margin"
android:id="@+id/oliveapp_start_button_layout"
tools:context=".liveness.SampleStartActivity">
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@mipmap/oliveapp_homepage_bg_portrait_phone"
android:scaleType="centerCrop" />
<!--关闭按钮-->
<ImageButton
android:id="@+id/oliveappCloseLivenessButton"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="@mipmap/oliveapp_close_icon"
app:layout_marginRightPercent="6.6%"
app:layout_marginTopPercent="6.8%"
app:layout_widthPercent="7%"
app:layout_aspectRatio="100%"/>
<Button
android:id="@+id/oliveappStartLivenessButton"
android:background="@drawable/oliveapp_start_button_selector"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
app:layout_marginBottomPercent="10%"
app:layout_widthPercent="73.5%"
app:layout_aspectRatio="513%"/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/oliveapp_start_button_layout"
xmlns:app="http://schemas.android.com/apk/res-auto">
<android.support.percent.PercentRelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@mipmap/oliveapp_homepage_bg_portrait_phone"/>
<!--关闭按钮-->
<ImageButton
android:id="@+id/oliveappCloseLivenessButton"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:background="@mipmap/oliveapp_close_icon"
app:layout_heightPercent="4.1%"
app:layout_aspectRatio="100%"
app:layout_marginRightPercent="6.6%"
app:layout_marginTopPercent="6.8%"/>
<Button
android:id="@+id/oliveappStartLivenessButton"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:background="@drawable/oliveapp_start_button_selector"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_marginBottomPercent="8%"
app:layout_widthPercent="73%"
app:layout_aspectRatio="513%"/>
</android.support.percent.PercentRelativeLayout>
</RelativeLayout>
<?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:background="@drawable/selector_item"
android:gravity="center_vertical"
android:minHeight="50dp"
android:orientation="horizontal"
android:paddingLeft="16dp"
android:paddingRight="16dp" >
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginTop="4dp" >
<TextView
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
android:singleLine="true"
android:text="title"
android:textColor="#4d4d4d"
android:textSize="18.0sp" />
<TextView
android:id="@android:id/summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_marginRight="20dp"
android:layout_toLeftOf="@android:id/widget_frame"
android:maxLines="2"
android:text="summary"
android:textColor="#AAAAAA"
android:textSize="16sp" />
<FrameLayout
android:id="@android:id/widget_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginLeft="4dp"
android:gravity="center_vertical" >
</FrameLayout>
</RelativeLayout>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
android:orientation="vertical" >
<ImageView
android:id="@android:id/icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="20dp" />
<TextView
android:id="@+id/value"
android:paddingTop="20dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="value"
android:textSize="20sp"
android:textColor="#aaaaaa" />
<SeekBar
android:id="@+id/seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="basicConfigList" translatable="false">
<item>动作个数</item>
<item>活体超时时间</item>
<item>固定动作序列</item>
</string-array>
<string-array name="actionCountsList" translatable="false">
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
<string-array name="fanpaiClsCountsList" translatable="false">
<item>1</item>
<item>3</item>
</string-array>
<string-array name="fanpaiClsThreshold" translatable="false">
<item>low</item>
<item>high</item>
</string-array>
<string-array name="livenessDectionOvertimeList_key" translatable="false">
<item>5秒</item>
<item>10秒</item>
<item>15秒</item>
<item>20秒</item>
<item>永不超时</item>
</string-array>
<string-array name="livenessDectionOvertimeList_value" translatable="false">
<item>5000</item>
<item>10000</item>
<item>15000</item>
<item>20000</item>
<item>1000000</item>
</string-array>
<string-array name="choiceActionSequenceList" translatable="false">
<item>张嘴</item>
<item>抬头</item>
<item>闭眼</item>
</string-array>
<string-array name="choiceActionSequenceList_value" translatable="false">
<item>1</item>
<item>53</item>
<item>3</item>
</string-array>
<string-array name="darkDetectEntry" translatable="false">
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
<string-array name="darkDetectValue" translatable="false">
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
</resources>
<resources>
<string name="oliveapp_result_hint_text_pass">Congratuation!</string>
<string name="oliveapp_result_hint_text_fail">Please retry!</string>
<string name="oliveapp_ready_hint_start">开始吧</string>
<string name="oliveapp_string_second"></string>
<string name="oliveapp_string_count_down">倒计时</string>
<string name="oliveapp_face_hint_focus_here">请正对手机屏幕</string>
<string name="oliveapp_face_database_image_hint_front">请拍摄身份证正面,确保人像和文字清晰</string>
<string name="oliveapp_face_database_image_hint_back">请拍摄身份证背面,确保文字清晰</string>
<string name="oliveapp_step_hint_focus">Please face the screen</string>
<string name="oliveapp_step_hint_mouthopen">Please open your mouth</string>
<string name="oliveapp_step_hint_eyeclose">Please blink</string>
<string name="oliveapp_step_hint_headup">Please head up</string>
</resources>
<resources>
<string name="oliveapp_detected_hint_none"></string>
<string name="oliveapp_detected_hint_face_not_found">请正对屏幕</string>
<string name="oliveapp_detected_hint_face_too_small_face">请靠近点</string>
<string name="oliveapp_detected_hint_face_too_large_face">请离远点</string>
<string name="oliveapp_detected_hint_light_too_bright">光线太亮了</string>
<string name="oliveapp_detected_hint_light_too_dark">光线太暗了</string>
<string name="oliveapp_detected_hint_face_side_face">请别侧脸</string>
<string name="oliveapp_detected_hint_face_up_face">请稍稍低头</string>
<string name="oliveapp_detected_hint_down_face">请稍稍抬头</string>
</resources>
<resources>
<string name="oliveapp_app_name">活体检测sample</string>
<string name="titleText">依图科技</string>
<string name="oliveapp_version">1.10.e</string>
<string name="subtitleText">活体检测Sample Code</string>
<string name="hintCamera">拍摄注册照</string>
<string name="hintFrontCamera">类证件照(自拍照)</string>
<string name="hintIdcardCapture">自动捕获身份证(正面)</string>
<string name="hintIdcardBackCapture">自动捕获身份证(反面)</string>
<string name="hintIDcard">翻拍证件照</string>
<string name="livenessButtonText">活体检测</string>
<string name="settingButtonText">测试专用</string>
<string name="title_activity_example_start">启动界面</string>
<string name="title_activity_example_result">结果展示界面</string>
<string name="title_activity_example_liveness">活体检测界面</string>
<string name="oliveapp_liveness_detection_pass_hint">恭喜您\n活体检测成功</string>
<string name="oliveapp_liveness_detection_fail_hint">检测失败\n请返回重试</string>
<string name="oliveapp_liveness_detection_cancel_hint">检测取消\n请返回重试</string>
</resources>
<resources>
<string name="title_activity_sample_idcard">SampleIdcardActivity</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="basicConfigList" translatable="false">
<item>动作个数</item>
<item>活体超时时间</item>
<item>固定动作序列</item>
</string-array>
<string-array name="actionCountsList" translatable="false">
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
<string-array name="fanpaiClsCountsList" translatable="false">
<item>1</item>
<item>3</item>
</string-array>
<string-array name="fanpaiClsThreshold" translatable="false">
<item>low</item>
<item>high</item>
</string-array>
<string-array name="livenessDectionOvertimeList_key" translatable="false">
<item>5秒</item>
<item>10秒</item>
<item>15秒</item>
<item>20秒</item>
<item>永不超时</item>
</string-array>
<string-array name="livenessDectionOvertimeList_value" translatable="false">
<item>5000</item>
<item>10000</item>
<item>15000</item>
<item>20000</item>
<item>1000000</item>
</string-array>
<string-array name="choiceActionSequenceList" translatable="false">
<item>张嘴</item>
<item>抬头</item>
<item>闭眼</item>
</string-array>
<string-array name="choiceActionSequenceList_value" translatable="false">
<item>1</item>
<item>53</item>
<item>3</item>
</string-array>
<string-array name="darkDetectEntry" translatable="false">
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
<string-array name="darkDetectValue" translatable="false">
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
</resources>
<resources>
<string name="oliveapp_result_hint_text_pass">Congratuation!</string>
<string name="oliveapp_result_hint_text_fail">Please retry!</string>
<string name="oliveapp_ready_hint_start">开始吧</string>
<string name="oliveapp_string_second"></string>
<string name="oliveapp_string_count_down">倒计时</string>
<string name="oliveapp_face_hint_focus_here">请正对手机屏幕</string>
<string name="oliveapp_face_database_image_hint_front">请拍摄身份证正面,确保人像和文字清晰</string>
<string name="oliveapp_face_database_image_hint_back">请拍摄身份证背面,确保文字清晰</string>
<string name="oliveapp_step_hint_focus">Silakan hadapi layar</string>
<string name="oliveapp_step_hint_mouthopen">Tolong buka mulutmu</string>
<string name="oliveapp_step_hint_eyeclose">Tolong berkedip</string>
<string name="oliveapp_step_hint_headup">Tolong angkat kepalamu</string>
</resources>
<resources>
<string name="oliveapp_detected_hint_none"></string>
<string name="oliveapp_detected_hint_face_not_found">请正对屏幕</string>
<string name="oliveapp_detected_hint_face_too_small_face">请靠近点</string>
<string name="oliveapp_detected_hint_face_too_large_face">请离远点</string>
<string name="oliveapp_detected_hint_light_too_bright">光线太亮了</string>
<string name="oliveapp_detected_hint_light_too_dark">光线太暗了</string>
<string name="oliveapp_detected_hint_face_side_face">请别侧脸</string>
<string name="oliveapp_detected_hint_face_up_face">请稍稍低头</string>
<string name="oliveapp_detected_hint_down_face">请稍稍抬头</string>
</resources>
<resources>
<string name="oliveapp_app_name">活体检测sample</string>
<string name="titleText">依图科技</string>
<string name="oliveapp_version">1.10.e</string>
<string name="subtitleText">活体检测Sample Code</string>
<string name="hintCamera">拍摄注册照</string>
<string name="hintFrontCamera">类证件照(自拍照)</string>
<string name="hintIdcardCapture">自动捕获身份证(正面)</string>
<string name="hintIdcardBackCapture">自动捕获身份证(反面)</string>
<string name="hintIDcard">翻拍证件照</string>
<string name="livenessButtonText">活体检测</string>
<string name="settingButtonText">测试专用</string>
<string name="title_activity_example_start">启动界面</string>
<string name="title_activity_example_result">结果展示界面</string>
<string name="title_activity_example_liveness">活体检测界面</string>
<string name="oliveapp_liveness_detection_pass_hint">恭喜您\n活体检测成功</string>
<string name="oliveapp_liveness_detection_fail_hint">检测失败\n请返回重试</string>
<string name="oliveapp_liveness_detection_cancel_hint">检测取消\n请返回重试</string>
</resources>
<resources>
<string name="title_activity_sample_idcard">SampleIdcardActivity</string>
</resources>
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>
<resources>
<!-- Example customization of dimensions originally defined in res/values/oliveapp_dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="oliveapp_activity_horizontal_margin">0dp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="basicConfigList" translatable="false">
<item>动作个数</item>
<item>活体超时时间</item>
<item>固定动作序列</item>
</string-array>
<string-array name="actionCountsList" translatable="false">
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
<string-array name="fanpaiClsCountsList" translatable="false">
<item>1</item>
<item>3</item>
</string-array>
<string-array name="fanpaiClsThreshold" translatable="false">
<item>low</item>
<item>high</item>
</string-array>
<string-array name="livenessDectionOvertimeList_key" translatable="false">
<item>5秒</item>
<item>10秒</item>
<item>15秒</item>
<item>20秒</item>
<item>永不超时</item>
</string-array>
<string-array name="livenessDectionOvertimeList_value" translatable="false">
<item>5000</item>
<item>10000</item>
<item>15000</item>
<item>20000</item>
<item>1000000</item>
</string-array>
<string-array name="choiceActionSequÓnceList" translatable="false">
<item>张嘴</item>
<item>抬头</item>
<item>闭眼</item>
</string-array>
<string-array name="choiceActionSequenceList_value" translatable="false">
<item>1</item>
<item>53</item>
<item>3</item>
</string-array>
<string-array name="darkDetectEntry" translatable="false">
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
<string-array name="darkDetectValue" translatable="false">
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
</resources>
<resources>
<string name="oliveapp_result_hint_text_pass">Congratuation!</string>
<string name="oliveapp_result_hint_text_fail">Please retry!</string>
<string name="oliveapp_ready_hint_start">开始吧</string>
<string name="oliveapp_string_second"></string>
<string name="oliveapp_string_count_down">倒计时</string>
<string name="oliveapp_face_hint_focus_here">请正对手机屏幕</string>
<string name="oliveapp_face_database_image_hint_front">请拍摄身份证正面,确保人像和文字清晰</string>
<string name="oliveapp_face_database_image_hint_back">请拍摄身份证背面,确保文字清晰</string>
<string name="oliveapp_step_hint_focus">Silakan hadapi layar</string>
<string name="oliveapp_step_hint_mouthopen">Tolong buka mulutmu</string>
<string name="oliveapp_step_hint_eyeclose">Tolong berkedip</string>
<string name="oliveapp_step_hint_headup">Tolong angkat kepalamu</string>
</resources>
<resources>
<string name="oliveapp_detected_hint_none"></string>
<string name="oliveapp_detected_hint_face_not_found">请正对屏幕</string>
<string name="oliveapp_detected_hint_face_too_small_face">请靠近点</string>
<string name="oliveapp_detected_hint_face_too_large_face">请离远点</string>
<string name="oliveapp_detected_hint_light_too_bright">光线太亮了</string>
<string name="oliveapp_detected_hint_light_too_dark">光线太暗了</string>
<string name="oliveapp_detected_hint_face_side_face">请别侧脸</string>
<string name="oliveapp_detected_hint_face_up_face">请稍稍低头</string>
<string name="oliveapp_detected_hint_down_face">请稍稍抬头</string>
</resources>
<resources>
<string name="oliveapp_app_name">活体检测sample</string>
<string name="titleText">依图科技</string>
<string name="oliveapp_version">1.10.e</string>
<string name="subtitleText">活体检测Sample Code</string>
<string name="hintCamera">拍摄注册照</string>
<string name="hintFrontCamera">类证件照(自拍照)</string>
<string name="hintIdcardCapture">自动捕获身份证(正面)</string>
<string name="hintIdcardBackCapture">自动捕获身份证(反面)</string>
<string name="hintIDcard">翻拍证件照</string>
<string name="livenessButtonText">活体检测</string>
<string name="settingButtonText">测试专用</string>
<string name="title_activity_example_start">启动界面</string>
<string name="title_activity_example_result">结果展示界面</string>
<string name="title_activity_example_liveness">活体检测界面</string>
<string name="oliveapp_liveness_detection_pass_hint">恭喜您\n活体检测成功</string>
<string name="oliveapp_liveness_detection_fail_hint">检测失败\n请返回重试</string>
<string name="oliveapp_liveness_detection_cancel_hint">检测取消\n请返回重试</string>
</resources>
<resources>
<string name="title_activity_sample_idcard">SampleIdcardActivity</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="basicConfigList" translatable="false">
<item>动作个数</item>
<item>活体超时时间</item>
<item>固定动作序列</item>
</string-array>
<string-array name="actionCountsList" translatable="false">
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
<string-array name="fanpaiClsCountsList" translatable="false">
<item>1</item>
<item>3</item>
</string-array>
<string-array name="fanpaiClsThreshold" translatable="false">
<item>low</item>
<item>high</item>
</string-array>
<string-array name="livenessDectionOvertimeList_key" translatable="false">
<item>5秒</item>
<item>10秒</item>
<item>15秒</item>
<item>20秒</item>
<item>永不超时</item>
</string-array>
<string-array name="livenessDectionOvertimeList_value" translatable="false">
<item>5000</item>
<item>10000</item>
<item>15000</item>
<item>20000</item>
<item>1000000</item>
</string-array>
<string-array name="choiceActionSequenceList" translatable="false">
<item>张嘴</item>
<item>抬头</item>
<item>闭眼</item>
</string-array>
<string-array name="choiceActionSequenceList_value" translatable="false">
<item>1</item>
<item>53</item>
<item>3</item>
</string-array>
<string-array name="darkDetectEntry" translatable="false">
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
<string-array name="darkDetectValue" translatable="false">
<item></item>
<item></item>
<item></item>
<item></item>
</string-array>
</resources>
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<color name="colorWhite">#FFFFFF</color>
<color name="navy">#FFFFFF</color>
<color name="colorDefaultBackground">#1A223E</color>
<color name="colorTabButtonSelectText">#FFFFFF</color>
<color name="colorTabButtonText">#000000</color>
<color name="itemBgColor">#fefefe</color>
<color name="itemSelectColor">#f0f0f0</color>
<color name="listLineColor">#e6e6e6</color>
<color name="itemdisabled">#f3f3f4</color>
</resources>
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="oliveapp_activity_horizontal_margin">0dp</dimen>
<dimen name="oliveapp_activity_vertical_margin">0dp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FixedAspectLayout">
<attr name="oliveapp_aspectRatio" format="float"/>
<attr name="oliveapp_fixMode" format="integer">
<enum name="fixHeight" value="1"/>
<enum name="fixWidth" value="2"/>
</attr>
</declare-styleable>
</resources>
\ No newline at end of file
<resources>
<string name="oliveapp_result_hint_text_pass">Congratuation!</string>
<string name="oliveapp_result_hint_text_fail">Please retry!</string>
<string name="oliveapp_ready_hint_start">开始吧</string>
<string name="oliveapp_string_second"></string>
<string name="oliveapp_string_count_down">倒计时</string>
<string name="oliveapp_face_hint_focus_here">请正对手机屏幕</string>
<string name="oliveapp_face_database_image_hint_front">请拍摄身份证正面,确保人像和文字清晰</string>
<string name="oliveapp_face_database_image_hint_back">请拍摄身份证背面,确保文字清晰</string>
<string name="oliveapp_step_hint_focus">Silakan hadapi layar</string>
<string name="oliveapp_step_hint_mouthopen">Tolong buka mulutmu</string>
<string name="oliveapp_step_hint_eyeclose">Tolong berkedip</string>
<string name="oliveapp_step_hint_headup">Tolong angkat kepalamu</string>
</resources>
<resources>
<string name="oliveapp_detected_hint_none"></string>
<string name="oliveapp_detected_hint_face_not_found">请正对屏幕</string>
<string name="oliveapp_detected_hint_face_too_small_face">请靠近点</string>
<string name="oliveapp_detected_hint_face_too_large_face">请离远点</string>
<string name="oliveapp_detected_hint_light_too_bright">光线太亮了</string>
<string name="oliveapp_detected_hint_light_too_dark">光线太暗了</string>
<string name="oliveapp_detected_hint_face_side_face">请别侧脸</string>
<string name="oliveapp_detected_hint_face_up_face">请稍稍低头</string>
<string name="oliveapp_detected_hint_down_face">请稍稍抬头</string>
</resources>
<resources>
<string name="oliveapp_app_name">活体检测sample</string>
<string name="titleText">依图科技</string>
<string name="oliveapp_version">1.10.e</string>
<string name="subtitleText">活体检测Sample Code</string>
<string name="hintCamera">拍摄注册照</string>
<string name="hintFrontCamera">类证件照(自拍照)</string>
<string name="hintIdcardCapture">自动捕获身份证(正面)</string>
<string name="hintIdcardBackCapture">自动捕获身份证(反面)</string>
<string name="hintIDcard">翻拍证件照</string>
<string name="livenessButtonText">活体检测</string>
<string name="settingButtonText">测试专用</string>
<string name="title_activity_example_start">启动界面</string>
<string name="title_activity_example_result">结果展示界面</string>
<string name="title_activity_example_liveness">活体检测界面</string>
<string name="oliveapp_liveness_detection_pass_hint">恭喜您\n活体检测成功</string>
<string name="oliveapp_liveness_detection_fail_hint">检测失败\n请返回重试</string>
<string name="oliveapp_liveness_detection_cancel_hint">检测取消\n请返回重试</string>
</resources>
<resources>
<!-- Base application theme. -->
<style name="SampleAppTheme" parent="android:Theme.Holo.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:theme">@android:style/Theme.NoTitleBar.Fullscreen</item>
</style>
</resources>
<resources>
<string name="title_activity_sample_idcard">SampleIdcardActivity</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:key="pref_liveness_dection">
<PreferenceCategory android:title="模式">
<CheckBoxPreference
android:defaultValue="false"
android:key="pref_debug_mode"
android:layout="@layout/prefs_list_s_item"
android:title="debug模式" />
<CheckBoxPreference
android:defaultValue="true"
android:key="pref_with_prestart"
android:layout="@layout/prefs_list_s_item"
android:title="是否预检" />
<CheckBoxPreference
android:defaultValue="false"
android:key="pref_pad_landscape"
android:layout="@layout/prefs_list_s_item"
android:title="Pad是否横屏" />
</PreferenceCategory>
<PreferenceCategory android:title="SaaS配置">
<EditTextPreference
android:key = "pref_saas_url"
android:title="SaaS地址"
android:defaultValue = "http://staging.yitutech.com"
android:layout="@layout/prefs_list_s_item"
/>
<EditTextPreference
android:key = "pref_test_id"
android:title="TestId"
android:defaultValue = "testid"
android:layout="@layout/prefs_list_s_item"
/>
</PreferenceCategory>
<PreferenceCategory android:title="基础配置">
<ListPreference
android:defaultValue="3"
android:entries="@array/actionCountsList"
android:entryValues="@array/actionCountsList"
android:key="pref_action_counts_list"
android:layout="@layout/prefs_list_s_item"
android:title="动作个数"
android:widgetLayout="@layout/arrow_widget" />
<ListPreference
android:defaultValue="10000"
android:entries="@array/livenessDectionOvertimeList_key"
android:entryValues="@array/livenessDectionOvertimeList_value"
android:key="pref_liveness_detection_overtime_list"
android:layout="@layout/prefs_list_s_item"
android:title="活体超时时间"
android:widgetLayout="@layout/arrow_widget" />
<CheckBoxPreference
android:defaultValue="false"
android:key="pref_fix_action"
android:layout="@layout/prefs_list_s_item"
android:title="固定动作序列" />
</PreferenceCategory>
<PreferenceCategory
android:key="pref_action_sequence_category"
android:title="动作序列">
<ListPreference
android:defaultValue="3"
android:entries="@array/choiceActionSequenceList"
android:entryValues="@array/choiceActionSequenceList_value"
android:key="pref_action_one_list"
android:layout="@layout/prefs_list_s_item"
android:title="动作一"
android:widgetLayout="@layout/arrow_widget" />
<ListPreference
android:defaultValue="3"
android:entries="@array/choiceActionSequenceList"
android:entryValues="@array/choiceActionSequenceList_value"
android:key="pref_action_two_list"
android:layout="@layout/prefs_list_s_item"
android:title="动作二"
android:widgetLayout="@layout/arrow_widget" />
<ListPreference
android:defaultValue="3"
android:entries="@array/choiceActionSequenceList"
android:entryValues="@array/choiceActionSequenceList_value"
android:key="pref_action_three_list"
android:layout="@layout/prefs_list_s_item"
android:title="动作三"
android:widgetLayout="@layout/arrow_widget" />
</PreferenceCategory>
<PreferenceCategory android:title="防屏幕相关">
<ListPreference
android:defaultValue="1"
android:entries="@array/fanpaiClsCountsList"
android:entryValues="@array/fanpaiClsCountsList"
android:key="pref_fanpaicls_counts_list"
android:layout="@layout/prefs_list_s_item"
android:title="翻拍照数量"
android:widgetLayout="@layout/arrow_widget" />
<ListPreference
android:defaultValue="low"
android:entries="@array/fanpaiClsThreshold"
android:entryValues="@array/fanpaiClsThreshold"
android:key="pref_fanpaicls_threshold_list"
android:layout="@layout/prefs_list_s_item"
android:title="防屏幕翻拍阈值"
android:widgetLayout="@layout/arrow_widget" />
</PreferenceCategory>
<PreferenceCategory android:title="存储相关">
<CheckBoxPreference
android:defaultValue="false"
android:key="pref_save_rgb"
android:layout="@layout/prefs_list_s_item"
android:title="存rgb图" />
<CheckBoxPreference
android:defaultValue="false"
android:key="pref_save_origin_image"
android:layout="@layout/prefs_list_s_item"
android:title="存原图" />
<CheckBoxPreference
android:defaultValue="false"
android:key="pref_save_package"
android:layout="@layout/prefs_list_s_item"
android:title="存大礼包" />
<CheckBoxPreference
android:defaultValue="false"
android:key="pref_fanpaicls_image"
android:layout="@layout/prefs_list_s_item"
android:title="存翻拍照" />
<CheckBoxPreference
android:defaultValue="false"
android:key="pref_jpeg_image"
android:layout="@layout/prefs_list_s_item"
android:title="存JPEG" />
<CheckBoxPreference
android:defaultValue="true"
android:key="pref_new_package"
android:layout="@layout/prefs_list_s_item"
android:title="是否开启信息收集" />
</PreferenceCategory>
<PreferenceCategory android:title="昏暗检测相关">
<ListPreference
android:key="pref_dark_detect_list"
android:entries="@array/darkDetectEntry"
android:entryValues="@array/darkDetectValue"
android:layout="@layout/prefs_list_s_item"
android:widgetLayout="@layout/arrow_widget"
android:title="昏暗检测阈值"/>
</PreferenceCategory>
</PreferenceScreen>
package com.oliveapp.liveness.sample;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* To work on unit tests, switch the Test Artifact in the Build Variants view.
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
\ No newline at end of file
File added
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":yitu" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":yitu" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<afterSyncTasks>
<task>generateDebugSources</task>
</afterSyncTasks>
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
<option name="PROJECT_TYPE" value="1" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/apt/test/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTestDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/testDebug/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/shaders" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/shaders" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/test/shaders" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/attr" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/check-manifest" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/intermediate-jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaPrecompile" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jniLibs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/packaged-aidl" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/packagedAssets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/packaged_res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/public_res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/shaders" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/transforms" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
<orderEntry type="jdk" jdkName="Android API 26 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Gradle: com.android.support:animated-vector-drawable-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: libimagecapture-release:@aar" level="project" />
<orderEntry type="library" name="Gradle: liblivenessdetectionview2-release:@aar" level="project" />
<orderEntry type="library" name="Gradle: libidcardcaptor-release:@aar" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: junit:junit:4.12@jar" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:common:1.0.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-vector-drawable-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-core-ui-26.1.0" level="project" />
<orderEntry type="library" scope="TEST" name="Gradle: org.hamcrest:hamcrest-core:1.3@jar" level="project" />
<orderEntry type="library" name="Gradle: liblivenessdetector2-release:@aar" level="project" />
<orderEntry type="library" name="Gradle: libcommon-release:@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:appcompat-v7-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: android.arch.core:common:1.0.0@jar" level="project" />
<orderEntry type="library" name="Gradle: libcamera-release:@aar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-annotations:26.1.0@jar" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:percent-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: com.android.support:support-compat-26.1.0" level="project" />
<orderEntry type="library" name="Gradle: android.arch.lifecycle:runtime-1.0.0" level="project" />
</component>
</module>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment