diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + + + @@ -29,6 +31,7 @@ + + + @@ -29,6 +31,7 @@ + + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java new file mode 100644 index 0000000..4109e3c --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java @@ -0,0 +1,184 @@ +package com.casic.birmm.hxrq.ui; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.NonNull; + +import com.casic.birmm.hxrq.R; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.utils.ImageHelper; + +import java.io.IOException; +import java.util.List; +import java.util.Stack; + +import butterknife.BindView; + +public class FacePreViewActivity extends BaseActivity implements Camera.PreviewCallback { + + private static final int preViewWidth = 720; + private static final int preViewHeight = 1280; + @BindView(R.id.surfaceView) + SurfaceView surfaceView; + private SurfaceHolder mSurfaceHolder; + private Camera mCamera; + private ImageHelper imageHelper; + private Stack bitmapStack; + private boolean isCanLogin = true; + + @Override + public int initLayoutView() { + return R.layout.activity_face; + } + + @Override + protected void setupTopBarLayout() { + + } + + @Override + public void initData() { + imageHelper = new ImageHelper(this); + bitmapStack = new Stack<>(); + } + + @Override + public void initEvent() { + // 绑定SurfaceView,取得SurfaceHolder对象 + mSurfaceHolder = surfaceView.getHolder(); + mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + if (mCamera == null) { + //打开相机 + openCamera(); + } + try { + //预览画面 + mCamera.setPreviewDisplay(mSurfaceHolder); + } catch (IOException e) { + e.printStackTrace(); + } + //开始预览 + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + releaseCamera(); //释放相机资源 + } + }); + mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置 + } + + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + camera.addCallbackBuffer(data); + Camera.Size size = camera.getParameters().getPreviewSize();//必须是相机支持的预览尺寸,否则颜色YUV空间会错位 + Bitmap originBitmap = imageHelper.nv21ToBitmap(data, size.width, size.height); + //要使用Android内置的人脸识别,需要将Bitmap对象转为RGB_565格式,否则无法识别 +// Bitmap faceDetectorBitmap = originBitmap.copy(Bitmap.Config.RGB_565, true); +// FaceDetector.Face[] faces = new FaceDetector.Face[1]; +// FaceDetector faceDetector = new FaceDetector(faceDetectorBitmap.getWidth(), faceDetectorBitmap.getHeight(), 1); +// int faceSum = faceDetector.findFaces(faceDetectorBitmap, faces); +// if (faceSum == 1) { + bitmapStack.push(originBitmap); + if (bitmapStack.size() >= 5) {//当栈里有5张bitmap之后才开始识别 + if (isCanLogin) { + isCanLogin = false; + Bitmap bitmap = bitmapStack.pop(); + Intent intent = new Intent(); + intent.putExtra("imageToBase64", ImageHelper.imageToBase64(bitmap)); + setResult(Activity.RESULT_OK, intent); + finish(); + } else { + finish(); + } + } +// } else { +// Log.d(TAG, "detectorFace: 未检测到人脸"); +// } + } + + /** + * 打开相机 + */ + private void openCamera() { + try { + mCamera = Camera.open(1); + initParameters(mCamera); //初始化相机配置信息 + mCamera.setPreviewCallback(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化相机属性 + */ + private void initParameters(Camera camera) { + try { + Camera.Parameters mParameters = camera.getParameters(); + mParameters.setPreviewFormat(ImageFormat.NV21); //设置预览图片的格式 + //获取与指定宽高相等或最接近的尺寸 + //设置预览尺寸 + Camera.Size bestPreviewSize = obtainBestSize(preViewWidth, preViewHeight, mParameters.getSupportedPreviewSizes()); + mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height); + //设置保存图片尺寸 +// Camera.Size bestPicSize = obtainBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes()); +// mParameters.setPictureSize(bestPicSize.width, bestPicSize.height); + //对焦模式 + mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + camera.setDisplayOrientation(90); + camera.setParameters(mParameters); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取最合适的尺寸 + */ + private Camera.Size obtainBestSize(int targetWidth, int targetHeight, List sizeList) { + Camera.Size bestSize = null; + int targetRatio = targetHeight / targetWidth;//目标大小的宽高比 + int minDiff = targetRatio; + + for (Camera.Size size : sizeList) { + if (size.width == targetHeight && size.height == targetWidth) { + bestSize = size; + break; + } + int supportedRatio = (size.width / size.height); + if (Math.abs(supportedRatio - targetRatio) < minDiff) { + minDiff = Math.abs(supportedRatio - targetRatio); + bestSize = size; + } + } + return bestSize; + } + + /** + * 释放相机资源 + */ + private void releaseCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } +} diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java new file mode 100644 index 0000000..4109e3c --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java @@ -0,0 +1,184 @@ +package com.casic.birmm.hxrq.ui; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.NonNull; + +import com.casic.birmm.hxrq.R; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.utils.ImageHelper; + +import java.io.IOException; +import java.util.List; +import java.util.Stack; + +import butterknife.BindView; + +public class FacePreViewActivity extends BaseActivity implements Camera.PreviewCallback { + + private static final int preViewWidth = 720; + private static final int preViewHeight = 1280; + @BindView(R.id.surfaceView) + SurfaceView surfaceView; + private SurfaceHolder mSurfaceHolder; + private Camera mCamera; + private ImageHelper imageHelper; + private Stack bitmapStack; + private boolean isCanLogin = true; + + @Override + public int initLayoutView() { + return R.layout.activity_face; + } + + @Override + protected void setupTopBarLayout() { + + } + + @Override + public void initData() { + imageHelper = new ImageHelper(this); + bitmapStack = new Stack<>(); + } + + @Override + public void initEvent() { + // 绑定SurfaceView,取得SurfaceHolder对象 + mSurfaceHolder = surfaceView.getHolder(); + mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + if (mCamera == null) { + //打开相机 + openCamera(); + } + try { + //预览画面 + mCamera.setPreviewDisplay(mSurfaceHolder); + } catch (IOException e) { + e.printStackTrace(); + } + //开始预览 + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + releaseCamera(); //释放相机资源 + } + }); + mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置 + } + + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + camera.addCallbackBuffer(data); + Camera.Size size = camera.getParameters().getPreviewSize();//必须是相机支持的预览尺寸,否则颜色YUV空间会错位 + Bitmap originBitmap = imageHelper.nv21ToBitmap(data, size.width, size.height); + //要使用Android内置的人脸识别,需要将Bitmap对象转为RGB_565格式,否则无法识别 +// Bitmap faceDetectorBitmap = originBitmap.copy(Bitmap.Config.RGB_565, true); +// FaceDetector.Face[] faces = new FaceDetector.Face[1]; +// FaceDetector faceDetector = new FaceDetector(faceDetectorBitmap.getWidth(), faceDetectorBitmap.getHeight(), 1); +// int faceSum = faceDetector.findFaces(faceDetectorBitmap, faces); +// if (faceSum == 1) { + bitmapStack.push(originBitmap); + if (bitmapStack.size() >= 5) {//当栈里有5张bitmap之后才开始识别 + if (isCanLogin) { + isCanLogin = false; + Bitmap bitmap = bitmapStack.pop(); + Intent intent = new Intent(); + intent.putExtra("imageToBase64", ImageHelper.imageToBase64(bitmap)); + setResult(Activity.RESULT_OK, intent); + finish(); + } else { + finish(); + } + } +// } else { +// Log.d(TAG, "detectorFace: 未检测到人脸"); +// } + } + + /** + * 打开相机 + */ + private void openCamera() { + try { + mCamera = Camera.open(1); + initParameters(mCamera); //初始化相机配置信息 + mCamera.setPreviewCallback(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化相机属性 + */ + private void initParameters(Camera camera) { + try { + Camera.Parameters mParameters = camera.getParameters(); + mParameters.setPreviewFormat(ImageFormat.NV21); //设置预览图片的格式 + //获取与指定宽高相等或最接近的尺寸 + //设置预览尺寸 + Camera.Size bestPreviewSize = obtainBestSize(preViewWidth, preViewHeight, mParameters.getSupportedPreviewSizes()); + mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height); + //设置保存图片尺寸 +// Camera.Size bestPicSize = obtainBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes()); +// mParameters.setPictureSize(bestPicSize.width, bestPicSize.height); + //对焦模式 + mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + camera.setDisplayOrientation(90); + camera.setParameters(mParameters); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取最合适的尺寸 + */ + private Camera.Size obtainBestSize(int targetWidth, int targetHeight, List sizeList) { + Camera.Size bestSize = null; + int targetRatio = targetHeight / targetWidth;//目标大小的宽高比 + int minDiff = targetRatio; + + for (Camera.Size size : sizeList) { + if (size.width == targetHeight && size.height == targetWidth) { + bestSize = size; + break; + } + int supportedRatio = (size.width / size.height); + if (Math.abs(supportedRatio - targetRatio) < minDiff) { + minDiff = Math.abs(supportedRatio - targetRatio); + bestSize = size; + } + } + return bestSize; + } + + /** + * 释放相机资源 + */ + private void releaseCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java index 98aef9d..30c26c8 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java @@ -8,14 +8,15 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.Nullable; import com.casic.birmm.hxrq.R; -import com.casic.birmm.hxrq.base.DoubleClickExitActivity; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -28,23 +29,16 @@ import com.casic.birmm.hxrq.mvp.view.IFaceLoginView; import com.casic.birmm.hxrq.mvp.view.ILoginView; import com.casic.birmm.hxrq.mvp.view.IQrCodeDataView; -import com.casic.birmm.hxrq.utils.FileUtils; -import com.casic.birmm.hxrq.utils.GlideLoadEngine; +import com.casic.birmm.hxrq.utils.Constant; import com.casic.birmm.hxrq.utils.RSAUtils; import com.casic.birmm.hxrq.utils.SaveKeyValues; -import com.casic.birmm.hxrq.utils.StringHelper; import com.casic.birmm.hxrq.utils.TokenHelper; import com.google.gson.Gson; -import com.luck.picture.lib.PictureSelector; -import com.luck.picture.lib.config.PictureConfig; -import com.luck.picture.lib.config.PictureMimeType; -import com.luck.picture.lib.entity.LocalMedia; import com.qmuiteam.qmui.util.QMUIStatusBarHelper; import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUITipDialog; import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton; -import java.io.File; import java.security.PublicKey; import butterknife.BindView; @@ -53,15 +47,11 @@ import cn.bertsir.zbar.QrConfig; import cn.bertsir.zbar.QrManager; import cn.bertsir.zbar.view.ScanLineView; -import top.zibin.luban.CompressionPredicate; -import top.zibin.luban.Luban; -import top.zibin.luban.OnCompressListener; -public class LoginActivity extends DoubleClickExitActivity - implements View.OnClickListener, IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { +public class LoginActivity extends BaseActivity implements View.OnClickListener, + IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { private static final String TAG = "LoginActivity"; - @BindView(R.id.userNameView) EditText userNameView; @BindView(R.id.userPasswordView) @@ -76,8 +66,8 @@ private LoginPresenterImpl loginPresenter; private QrCodePresenterImpl qrCodePresenter; private FaceLoginPresenterImpl faceLoginPresenter; - private String userName; - private String userPassword; + private boolean isPasswordLogin = false; + private String qrCode = ""; @Override public int initLayoutView() { @@ -86,20 +76,29 @@ @Override protected void setupTopBarLayout() { - //TODO 此页面无需实现 + //设置状态栏黑色字体图标 + QMUIStatusBarHelper.setStatusBarLightMode(this); } @Override public void initData() { - //设置状态栏黑色字体图标 - QMUIStatusBarHelper.setStatusBarLightMode(this); - String userName = (String) SaveKeyValues.getValue("userName", ""); String userPassword = (String) SaveKeyValues.getValue("userPassword", ""); + userNameView.setText(userName); + userPasswordView.setText(userPassword); if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(userPassword)) { - userNameView.setText(userName); - userPasswordView.setText(userPassword); + rememberPasswordView.setChecked(true); + } else { + rememberPasswordView.setChecked(false); } + rememberPasswordView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!isChecked) { + SaveKeyValues.removeKey("userPassword"); + } + } + }); loadingDialog = new QMUITipDialog.Builder(this) .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING) .setTipWord("登陆中,请稍后") @@ -124,14 +123,9 @@ public void onClick(View v) { switch (v.getId()) { case R.id.loginButton: - userName = userNameView.getText().toString(); - userPassword = userPasswordView.getText().toString(); - if (rememberPasswordView.isChecked()) { - SaveKeyValues.putValue("userName", userName); - SaveKeyValues.putValue("userPassword", userPassword); - } //密码登录前需要验证sid authenticatePresenter.onReadyRetrofitRequest(); + isPasswordLogin = true; break; case R.id.changeLoginModeView: //首次登录不可用扫码,因为还未注册 @@ -169,50 +163,19 @@ } private void captureFaceData() { - //TODO 调相机,捕获人脸数据,并保存为文件得到路径 - PictureSelector.create(this) - .openCamera(PictureMimeType.ofImage()) - .imageEngine(GlideLoadEngine.createGlideEngine()) - .maxSelectNum(1) - .forResult(PictureConfig.REQUEST_CAMERA); + // 调相机,捕获人脸数据,并保存为文件得到路径 + startActivityForResult(new Intent(this, FacePreViewActivity.class), Constant.FACE_DETECTOR_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - if (requestCode == PictureConfig.REQUEST_CAMERA) { - LocalMedia localMedia = PictureSelector.obtainMultipleResult(data).get(0); - Luban.with(this) - .load(localMedia.getRealPath()) - .ignoreBy(100) - .setTargetDir(FileUtils.getFileDir("CompressImageFile")) - .filter(new CompressionPredicate() { - @Override - public boolean apply(String path) { - return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif")); - } - }) - .setCompressListener(new OnCompressListener() { - @Override - public void onStart() { - // TODO 压缩开始前调用,可以在方法内启动 loading UI - } - - @Override - public void onSuccess(File file) { - String imageToBase64 = StringHelper.imageToBase64(file); - - ImageBean imageBean = new ImageBean(); - imageBean.setImage(imageToBase64); - faceLoginPresenter.onReadyRetrofitRequest(imageBean); - } - - @Override - public void onError(Throwable e) { - // TODO 当压缩过程出现问题时调用 - } - }).launch(); + if (requestCode == Constant.FACE_DETECTOR_CODE) { + String imageToBase64 = data.getStringExtra("imageToBase64"); + ImageBean imageBean = new ImageBean(); + imageBean.setImage(imageToBase64); + faceLoginPresenter.onReadyRetrofitRequest(imageBean); } } } @@ -232,7 +195,7 @@ .setPlaySound(true)//是否扫描成功后bi~的声音 .setDingPath(R.raw.qrcode)//设置提示音(不设置为默认的Ding~) .setIsOnlyCenter(true)//是否只识别框中内容(默认为全屏识别) - .setTitleBackgroudColor(Color.parseColor("#262020"))//设置状态栏颜色 + .setTitleBackgroudColor(R.color.black)//设置状态栏颜色 .setTitleTextColor(Color.WHITE)//设置Title文字颜色 .setScreenOrientation(QrConfig.SCREEN_PORTRAIT)//设置屏幕方式 .setScanLineStyle(ScanLineView.style_hybrid)//扫描线样式 @@ -241,8 +204,8 @@ QrManager.getInstance().init(qrConfig).startScan(this, new QrManager.OnScanResultCallback() { @Override public void onScanSuccess(final ScanResult result) { -// Log.d(TAG, "扫码结果: " + result.content); - qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), result.content); + qrCode = result.content; + authenticatePresenter.onReadyRetrofitRequest();//需要时时保持最新token,所以扫码登录之前需要获取最新token } }); } @@ -254,9 +217,15 @@ @Override public void authenticateResult(PublicKeyBean result) { - Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); +// Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); if (result.isSuccess()) { PublicKey publicKey = RSAUtils.keyStrToPublicKey(result.getData().getPublicKey()); + String userName = userNameView.getText().toString(); + String userPassword = userPasswordView.getText().toString(); + if (rememberPasswordView.isChecked()) { + SaveKeyValues.putValue("userName", userName); + SaveKeyValues.putValue("userPassword", userPassword); + } if (TextUtils.isEmpty(userName)) { Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show(); return; @@ -266,7 +235,6 @@ return; } String dataByPublicKey = RSAUtils.encryptDataByPublicKey(userPassword.getBytes(), publicKey); - Log.d(TAG, "authenticateResult: 验证成功,开始登录"); //登录并获取Token,POST请求 loginPresenter.onReadyRetrofitRequest(result.getData().getSid(), userName, dataByPublicKey); } else { @@ -283,11 +251,14 @@ String token = result.getData().getToken(); if (!TextUtils.isEmpty(token)) { //获取用户信息 - Log.d(TAG, "obtainLoginResult: 获取Token成功"); TokenHelper.saveToken(token); //验证成功登录 - startActivity(new Intent(this, MainActivity.class)); - finish(); + if (isPasswordLogin) { + startActivity(new Intent(this, MainActivity.class)); + finish(); + } else { + qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), qrCode); + } } } @@ -307,15 +278,17 @@ } @Override - public void obtainFaceLoginData(FaceLoginResultBean resultBean) { -// Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); - if (resultBean.getCode() == 200) { + public void obtainFaceLoginData(FaceResultBean resultBean) { + Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); + if (resultBean.isSuccess()) { + //{"code":200,"data":{"kaptcha":"","token":"9135bcb7-4f39-4b7a-a10e-555406ddb9e1"},"exceptionClazz":"","message":"登录成功","success":true} TokenHelper.saveToken(resultBean.getData().getToken()); //验证成功登录 startActivity(new Intent(this, MainActivity.class)); finish(); } else { - Toast.makeText(this, "无法解析人脸", Toast.LENGTH_SHORT).show(); + //{"code":200,"data":"","exceptionClazz":"","message":"图片中没有人脸","success":false} + Toast.makeText(this, "人脸识别失败", Toast.LENGTH_SHORT).show(); } } @@ -336,5 +309,8 @@ if (qrCodePresenter != null) { qrCodePresenter.disposeRetrofitRequest(); } + if (faceLoginPresenter != null) { + faceLoginPresenter.disposeRetrofitRequest(); + } } -} +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java new file mode 100644 index 0000000..4109e3c --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java @@ -0,0 +1,184 @@ +package com.casic.birmm.hxrq.ui; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.NonNull; + +import com.casic.birmm.hxrq.R; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.utils.ImageHelper; + +import java.io.IOException; +import java.util.List; +import java.util.Stack; + +import butterknife.BindView; + +public class FacePreViewActivity extends BaseActivity implements Camera.PreviewCallback { + + private static final int preViewWidth = 720; + private static final int preViewHeight = 1280; + @BindView(R.id.surfaceView) + SurfaceView surfaceView; + private SurfaceHolder mSurfaceHolder; + private Camera mCamera; + private ImageHelper imageHelper; + private Stack bitmapStack; + private boolean isCanLogin = true; + + @Override + public int initLayoutView() { + return R.layout.activity_face; + } + + @Override + protected void setupTopBarLayout() { + + } + + @Override + public void initData() { + imageHelper = new ImageHelper(this); + bitmapStack = new Stack<>(); + } + + @Override + public void initEvent() { + // 绑定SurfaceView,取得SurfaceHolder对象 + mSurfaceHolder = surfaceView.getHolder(); + mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + if (mCamera == null) { + //打开相机 + openCamera(); + } + try { + //预览画面 + mCamera.setPreviewDisplay(mSurfaceHolder); + } catch (IOException e) { + e.printStackTrace(); + } + //开始预览 + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + releaseCamera(); //释放相机资源 + } + }); + mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置 + } + + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + camera.addCallbackBuffer(data); + Camera.Size size = camera.getParameters().getPreviewSize();//必须是相机支持的预览尺寸,否则颜色YUV空间会错位 + Bitmap originBitmap = imageHelper.nv21ToBitmap(data, size.width, size.height); + //要使用Android内置的人脸识别,需要将Bitmap对象转为RGB_565格式,否则无法识别 +// Bitmap faceDetectorBitmap = originBitmap.copy(Bitmap.Config.RGB_565, true); +// FaceDetector.Face[] faces = new FaceDetector.Face[1]; +// FaceDetector faceDetector = new FaceDetector(faceDetectorBitmap.getWidth(), faceDetectorBitmap.getHeight(), 1); +// int faceSum = faceDetector.findFaces(faceDetectorBitmap, faces); +// if (faceSum == 1) { + bitmapStack.push(originBitmap); + if (bitmapStack.size() >= 5) {//当栈里有5张bitmap之后才开始识别 + if (isCanLogin) { + isCanLogin = false; + Bitmap bitmap = bitmapStack.pop(); + Intent intent = new Intent(); + intent.putExtra("imageToBase64", ImageHelper.imageToBase64(bitmap)); + setResult(Activity.RESULT_OK, intent); + finish(); + } else { + finish(); + } + } +// } else { +// Log.d(TAG, "detectorFace: 未检测到人脸"); +// } + } + + /** + * 打开相机 + */ + private void openCamera() { + try { + mCamera = Camera.open(1); + initParameters(mCamera); //初始化相机配置信息 + mCamera.setPreviewCallback(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化相机属性 + */ + private void initParameters(Camera camera) { + try { + Camera.Parameters mParameters = camera.getParameters(); + mParameters.setPreviewFormat(ImageFormat.NV21); //设置预览图片的格式 + //获取与指定宽高相等或最接近的尺寸 + //设置预览尺寸 + Camera.Size bestPreviewSize = obtainBestSize(preViewWidth, preViewHeight, mParameters.getSupportedPreviewSizes()); + mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height); + //设置保存图片尺寸 +// Camera.Size bestPicSize = obtainBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes()); +// mParameters.setPictureSize(bestPicSize.width, bestPicSize.height); + //对焦模式 + mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + camera.setDisplayOrientation(90); + camera.setParameters(mParameters); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取最合适的尺寸 + */ + private Camera.Size obtainBestSize(int targetWidth, int targetHeight, List sizeList) { + Camera.Size bestSize = null; + int targetRatio = targetHeight / targetWidth;//目标大小的宽高比 + int minDiff = targetRatio; + + for (Camera.Size size : sizeList) { + if (size.width == targetHeight && size.height == targetWidth) { + bestSize = size; + break; + } + int supportedRatio = (size.width / size.height); + if (Math.abs(supportedRatio - targetRatio) < minDiff) { + minDiff = Math.abs(supportedRatio - targetRatio); + bestSize = size; + } + } + return bestSize; + } + + /** + * 释放相机资源 + */ + private void releaseCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java index 98aef9d..30c26c8 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java @@ -8,14 +8,15 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.Nullable; import com.casic.birmm.hxrq.R; -import com.casic.birmm.hxrq.base.DoubleClickExitActivity; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -28,23 +29,16 @@ import com.casic.birmm.hxrq.mvp.view.IFaceLoginView; import com.casic.birmm.hxrq.mvp.view.ILoginView; import com.casic.birmm.hxrq.mvp.view.IQrCodeDataView; -import com.casic.birmm.hxrq.utils.FileUtils; -import com.casic.birmm.hxrq.utils.GlideLoadEngine; +import com.casic.birmm.hxrq.utils.Constant; import com.casic.birmm.hxrq.utils.RSAUtils; import com.casic.birmm.hxrq.utils.SaveKeyValues; -import com.casic.birmm.hxrq.utils.StringHelper; import com.casic.birmm.hxrq.utils.TokenHelper; import com.google.gson.Gson; -import com.luck.picture.lib.PictureSelector; -import com.luck.picture.lib.config.PictureConfig; -import com.luck.picture.lib.config.PictureMimeType; -import com.luck.picture.lib.entity.LocalMedia; import com.qmuiteam.qmui.util.QMUIStatusBarHelper; import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUITipDialog; import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton; -import java.io.File; import java.security.PublicKey; import butterknife.BindView; @@ -53,15 +47,11 @@ import cn.bertsir.zbar.QrConfig; import cn.bertsir.zbar.QrManager; import cn.bertsir.zbar.view.ScanLineView; -import top.zibin.luban.CompressionPredicate; -import top.zibin.luban.Luban; -import top.zibin.luban.OnCompressListener; -public class LoginActivity extends DoubleClickExitActivity - implements View.OnClickListener, IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { +public class LoginActivity extends BaseActivity implements View.OnClickListener, + IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { private static final String TAG = "LoginActivity"; - @BindView(R.id.userNameView) EditText userNameView; @BindView(R.id.userPasswordView) @@ -76,8 +66,8 @@ private LoginPresenterImpl loginPresenter; private QrCodePresenterImpl qrCodePresenter; private FaceLoginPresenterImpl faceLoginPresenter; - private String userName; - private String userPassword; + private boolean isPasswordLogin = false; + private String qrCode = ""; @Override public int initLayoutView() { @@ -86,20 +76,29 @@ @Override protected void setupTopBarLayout() { - //TODO 此页面无需实现 + //设置状态栏黑色字体图标 + QMUIStatusBarHelper.setStatusBarLightMode(this); } @Override public void initData() { - //设置状态栏黑色字体图标 - QMUIStatusBarHelper.setStatusBarLightMode(this); - String userName = (String) SaveKeyValues.getValue("userName", ""); String userPassword = (String) SaveKeyValues.getValue("userPassword", ""); + userNameView.setText(userName); + userPasswordView.setText(userPassword); if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(userPassword)) { - userNameView.setText(userName); - userPasswordView.setText(userPassword); + rememberPasswordView.setChecked(true); + } else { + rememberPasswordView.setChecked(false); } + rememberPasswordView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!isChecked) { + SaveKeyValues.removeKey("userPassword"); + } + } + }); loadingDialog = new QMUITipDialog.Builder(this) .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING) .setTipWord("登陆中,请稍后") @@ -124,14 +123,9 @@ public void onClick(View v) { switch (v.getId()) { case R.id.loginButton: - userName = userNameView.getText().toString(); - userPassword = userPasswordView.getText().toString(); - if (rememberPasswordView.isChecked()) { - SaveKeyValues.putValue("userName", userName); - SaveKeyValues.putValue("userPassword", userPassword); - } //密码登录前需要验证sid authenticatePresenter.onReadyRetrofitRequest(); + isPasswordLogin = true; break; case R.id.changeLoginModeView: //首次登录不可用扫码,因为还未注册 @@ -169,50 +163,19 @@ } private void captureFaceData() { - //TODO 调相机,捕获人脸数据,并保存为文件得到路径 - PictureSelector.create(this) - .openCamera(PictureMimeType.ofImage()) - .imageEngine(GlideLoadEngine.createGlideEngine()) - .maxSelectNum(1) - .forResult(PictureConfig.REQUEST_CAMERA); + // 调相机,捕获人脸数据,并保存为文件得到路径 + startActivityForResult(new Intent(this, FacePreViewActivity.class), Constant.FACE_DETECTOR_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - if (requestCode == PictureConfig.REQUEST_CAMERA) { - LocalMedia localMedia = PictureSelector.obtainMultipleResult(data).get(0); - Luban.with(this) - .load(localMedia.getRealPath()) - .ignoreBy(100) - .setTargetDir(FileUtils.getFileDir("CompressImageFile")) - .filter(new CompressionPredicate() { - @Override - public boolean apply(String path) { - return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif")); - } - }) - .setCompressListener(new OnCompressListener() { - @Override - public void onStart() { - // TODO 压缩开始前调用,可以在方法内启动 loading UI - } - - @Override - public void onSuccess(File file) { - String imageToBase64 = StringHelper.imageToBase64(file); - - ImageBean imageBean = new ImageBean(); - imageBean.setImage(imageToBase64); - faceLoginPresenter.onReadyRetrofitRequest(imageBean); - } - - @Override - public void onError(Throwable e) { - // TODO 当压缩过程出现问题时调用 - } - }).launch(); + if (requestCode == Constant.FACE_DETECTOR_CODE) { + String imageToBase64 = data.getStringExtra("imageToBase64"); + ImageBean imageBean = new ImageBean(); + imageBean.setImage(imageToBase64); + faceLoginPresenter.onReadyRetrofitRequest(imageBean); } } } @@ -232,7 +195,7 @@ .setPlaySound(true)//是否扫描成功后bi~的声音 .setDingPath(R.raw.qrcode)//设置提示音(不设置为默认的Ding~) .setIsOnlyCenter(true)//是否只识别框中内容(默认为全屏识别) - .setTitleBackgroudColor(Color.parseColor("#262020"))//设置状态栏颜色 + .setTitleBackgroudColor(R.color.black)//设置状态栏颜色 .setTitleTextColor(Color.WHITE)//设置Title文字颜色 .setScreenOrientation(QrConfig.SCREEN_PORTRAIT)//设置屏幕方式 .setScanLineStyle(ScanLineView.style_hybrid)//扫描线样式 @@ -241,8 +204,8 @@ QrManager.getInstance().init(qrConfig).startScan(this, new QrManager.OnScanResultCallback() { @Override public void onScanSuccess(final ScanResult result) { -// Log.d(TAG, "扫码结果: " + result.content); - qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), result.content); + qrCode = result.content; + authenticatePresenter.onReadyRetrofitRequest();//需要时时保持最新token,所以扫码登录之前需要获取最新token } }); } @@ -254,9 +217,15 @@ @Override public void authenticateResult(PublicKeyBean result) { - Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); +// Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); if (result.isSuccess()) { PublicKey publicKey = RSAUtils.keyStrToPublicKey(result.getData().getPublicKey()); + String userName = userNameView.getText().toString(); + String userPassword = userPasswordView.getText().toString(); + if (rememberPasswordView.isChecked()) { + SaveKeyValues.putValue("userName", userName); + SaveKeyValues.putValue("userPassword", userPassword); + } if (TextUtils.isEmpty(userName)) { Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show(); return; @@ -266,7 +235,6 @@ return; } String dataByPublicKey = RSAUtils.encryptDataByPublicKey(userPassword.getBytes(), publicKey); - Log.d(TAG, "authenticateResult: 验证成功,开始登录"); //登录并获取Token,POST请求 loginPresenter.onReadyRetrofitRequest(result.getData().getSid(), userName, dataByPublicKey); } else { @@ -283,11 +251,14 @@ String token = result.getData().getToken(); if (!TextUtils.isEmpty(token)) { //获取用户信息 - Log.d(TAG, "obtainLoginResult: 获取Token成功"); TokenHelper.saveToken(token); //验证成功登录 - startActivity(new Intent(this, MainActivity.class)); - finish(); + if (isPasswordLogin) { + startActivity(new Intent(this, MainActivity.class)); + finish(); + } else { + qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), qrCode); + } } } @@ -307,15 +278,17 @@ } @Override - public void obtainFaceLoginData(FaceLoginResultBean resultBean) { -// Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); - if (resultBean.getCode() == 200) { + public void obtainFaceLoginData(FaceResultBean resultBean) { + Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); + if (resultBean.isSuccess()) { + //{"code":200,"data":{"kaptcha":"","token":"9135bcb7-4f39-4b7a-a10e-555406ddb9e1"},"exceptionClazz":"","message":"登录成功","success":true} TokenHelper.saveToken(resultBean.getData().getToken()); //验证成功登录 startActivity(new Intent(this, MainActivity.class)); finish(); } else { - Toast.makeText(this, "无法解析人脸", Toast.LENGTH_SHORT).show(); + //{"code":200,"data":"","exceptionClazz":"","message":"图片中没有人脸","success":false} + Toast.makeText(this, "人脸识别失败", Toast.LENGTH_SHORT).show(); } } @@ -336,5 +309,8 @@ if (qrCodePresenter != null) { qrCodePresenter.disposeRetrofitRequest(); } + if (faceLoginPresenter != null) { + faceLoginPresenter.disposeRetrofitRequest(); + } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java index e8e9b75..759a94d 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java @@ -9,4 +9,5 @@ Manifest.permission.WRITE_EXTERNAL_STORAGE}; public static final int PERMISSIONS_CODE = 999; + public static final int FACE_DETECTOR_CODE = 998; } diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java new file mode 100644 index 0000000..4109e3c --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java @@ -0,0 +1,184 @@ +package com.casic.birmm.hxrq.ui; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.NonNull; + +import com.casic.birmm.hxrq.R; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.utils.ImageHelper; + +import java.io.IOException; +import java.util.List; +import java.util.Stack; + +import butterknife.BindView; + +public class FacePreViewActivity extends BaseActivity implements Camera.PreviewCallback { + + private static final int preViewWidth = 720; + private static final int preViewHeight = 1280; + @BindView(R.id.surfaceView) + SurfaceView surfaceView; + private SurfaceHolder mSurfaceHolder; + private Camera mCamera; + private ImageHelper imageHelper; + private Stack bitmapStack; + private boolean isCanLogin = true; + + @Override + public int initLayoutView() { + return R.layout.activity_face; + } + + @Override + protected void setupTopBarLayout() { + + } + + @Override + public void initData() { + imageHelper = new ImageHelper(this); + bitmapStack = new Stack<>(); + } + + @Override + public void initEvent() { + // 绑定SurfaceView,取得SurfaceHolder对象 + mSurfaceHolder = surfaceView.getHolder(); + mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + if (mCamera == null) { + //打开相机 + openCamera(); + } + try { + //预览画面 + mCamera.setPreviewDisplay(mSurfaceHolder); + } catch (IOException e) { + e.printStackTrace(); + } + //开始预览 + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + releaseCamera(); //释放相机资源 + } + }); + mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置 + } + + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + camera.addCallbackBuffer(data); + Camera.Size size = camera.getParameters().getPreviewSize();//必须是相机支持的预览尺寸,否则颜色YUV空间会错位 + Bitmap originBitmap = imageHelper.nv21ToBitmap(data, size.width, size.height); + //要使用Android内置的人脸识别,需要将Bitmap对象转为RGB_565格式,否则无法识别 +// Bitmap faceDetectorBitmap = originBitmap.copy(Bitmap.Config.RGB_565, true); +// FaceDetector.Face[] faces = new FaceDetector.Face[1]; +// FaceDetector faceDetector = new FaceDetector(faceDetectorBitmap.getWidth(), faceDetectorBitmap.getHeight(), 1); +// int faceSum = faceDetector.findFaces(faceDetectorBitmap, faces); +// if (faceSum == 1) { + bitmapStack.push(originBitmap); + if (bitmapStack.size() >= 5) {//当栈里有5张bitmap之后才开始识别 + if (isCanLogin) { + isCanLogin = false; + Bitmap bitmap = bitmapStack.pop(); + Intent intent = new Intent(); + intent.putExtra("imageToBase64", ImageHelper.imageToBase64(bitmap)); + setResult(Activity.RESULT_OK, intent); + finish(); + } else { + finish(); + } + } +// } else { +// Log.d(TAG, "detectorFace: 未检测到人脸"); +// } + } + + /** + * 打开相机 + */ + private void openCamera() { + try { + mCamera = Camera.open(1); + initParameters(mCamera); //初始化相机配置信息 + mCamera.setPreviewCallback(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化相机属性 + */ + private void initParameters(Camera camera) { + try { + Camera.Parameters mParameters = camera.getParameters(); + mParameters.setPreviewFormat(ImageFormat.NV21); //设置预览图片的格式 + //获取与指定宽高相等或最接近的尺寸 + //设置预览尺寸 + Camera.Size bestPreviewSize = obtainBestSize(preViewWidth, preViewHeight, mParameters.getSupportedPreviewSizes()); + mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height); + //设置保存图片尺寸 +// Camera.Size bestPicSize = obtainBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes()); +// mParameters.setPictureSize(bestPicSize.width, bestPicSize.height); + //对焦模式 + mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + camera.setDisplayOrientation(90); + camera.setParameters(mParameters); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取最合适的尺寸 + */ + private Camera.Size obtainBestSize(int targetWidth, int targetHeight, List sizeList) { + Camera.Size bestSize = null; + int targetRatio = targetHeight / targetWidth;//目标大小的宽高比 + int minDiff = targetRatio; + + for (Camera.Size size : sizeList) { + if (size.width == targetHeight && size.height == targetWidth) { + bestSize = size; + break; + } + int supportedRatio = (size.width / size.height); + if (Math.abs(supportedRatio - targetRatio) < minDiff) { + minDiff = Math.abs(supportedRatio - targetRatio); + bestSize = size; + } + } + return bestSize; + } + + /** + * 释放相机资源 + */ + private void releaseCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java index 98aef9d..30c26c8 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java @@ -8,14 +8,15 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.Nullable; import com.casic.birmm.hxrq.R; -import com.casic.birmm.hxrq.base.DoubleClickExitActivity; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -28,23 +29,16 @@ import com.casic.birmm.hxrq.mvp.view.IFaceLoginView; import com.casic.birmm.hxrq.mvp.view.ILoginView; import com.casic.birmm.hxrq.mvp.view.IQrCodeDataView; -import com.casic.birmm.hxrq.utils.FileUtils; -import com.casic.birmm.hxrq.utils.GlideLoadEngine; +import com.casic.birmm.hxrq.utils.Constant; import com.casic.birmm.hxrq.utils.RSAUtils; import com.casic.birmm.hxrq.utils.SaveKeyValues; -import com.casic.birmm.hxrq.utils.StringHelper; import com.casic.birmm.hxrq.utils.TokenHelper; import com.google.gson.Gson; -import com.luck.picture.lib.PictureSelector; -import com.luck.picture.lib.config.PictureConfig; -import com.luck.picture.lib.config.PictureMimeType; -import com.luck.picture.lib.entity.LocalMedia; import com.qmuiteam.qmui.util.QMUIStatusBarHelper; import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUITipDialog; import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton; -import java.io.File; import java.security.PublicKey; import butterknife.BindView; @@ -53,15 +47,11 @@ import cn.bertsir.zbar.QrConfig; import cn.bertsir.zbar.QrManager; import cn.bertsir.zbar.view.ScanLineView; -import top.zibin.luban.CompressionPredicate; -import top.zibin.luban.Luban; -import top.zibin.luban.OnCompressListener; -public class LoginActivity extends DoubleClickExitActivity - implements View.OnClickListener, IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { +public class LoginActivity extends BaseActivity implements View.OnClickListener, + IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { private static final String TAG = "LoginActivity"; - @BindView(R.id.userNameView) EditText userNameView; @BindView(R.id.userPasswordView) @@ -76,8 +66,8 @@ private LoginPresenterImpl loginPresenter; private QrCodePresenterImpl qrCodePresenter; private FaceLoginPresenterImpl faceLoginPresenter; - private String userName; - private String userPassword; + private boolean isPasswordLogin = false; + private String qrCode = ""; @Override public int initLayoutView() { @@ -86,20 +76,29 @@ @Override protected void setupTopBarLayout() { - //TODO 此页面无需实现 + //设置状态栏黑色字体图标 + QMUIStatusBarHelper.setStatusBarLightMode(this); } @Override public void initData() { - //设置状态栏黑色字体图标 - QMUIStatusBarHelper.setStatusBarLightMode(this); - String userName = (String) SaveKeyValues.getValue("userName", ""); String userPassword = (String) SaveKeyValues.getValue("userPassword", ""); + userNameView.setText(userName); + userPasswordView.setText(userPassword); if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(userPassword)) { - userNameView.setText(userName); - userPasswordView.setText(userPassword); + rememberPasswordView.setChecked(true); + } else { + rememberPasswordView.setChecked(false); } + rememberPasswordView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!isChecked) { + SaveKeyValues.removeKey("userPassword"); + } + } + }); loadingDialog = new QMUITipDialog.Builder(this) .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING) .setTipWord("登陆中,请稍后") @@ -124,14 +123,9 @@ public void onClick(View v) { switch (v.getId()) { case R.id.loginButton: - userName = userNameView.getText().toString(); - userPassword = userPasswordView.getText().toString(); - if (rememberPasswordView.isChecked()) { - SaveKeyValues.putValue("userName", userName); - SaveKeyValues.putValue("userPassword", userPassword); - } //密码登录前需要验证sid authenticatePresenter.onReadyRetrofitRequest(); + isPasswordLogin = true; break; case R.id.changeLoginModeView: //首次登录不可用扫码,因为还未注册 @@ -169,50 +163,19 @@ } private void captureFaceData() { - //TODO 调相机,捕获人脸数据,并保存为文件得到路径 - PictureSelector.create(this) - .openCamera(PictureMimeType.ofImage()) - .imageEngine(GlideLoadEngine.createGlideEngine()) - .maxSelectNum(1) - .forResult(PictureConfig.REQUEST_CAMERA); + // 调相机,捕获人脸数据,并保存为文件得到路径 + startActivityForResult(new Intent(this, FacePreViewActivity.class), Constant.FACE_DETECTOR_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - if (requestCode == PictureConfig.REQUEST_CAMERA) { - LocalMedia localMedia = PictureSelector.obtainMultipleResult(data).get(0); - Luban.with(this) - .load(localMedia.getRealPath()) - .ignoreBy(100) - .setTargetDir(FileUtils.getFileDir("CompressImageFile")) - .filter(new CompressionPredicate() { - @Override - public boolean apply(String path) { - return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif")); - } - }) - .setCompressListener(new OnCompressListener() { - @Override - public void onStart() { - // TODO 压缩开始前调用,可以在方法内启动 loading UI - } - - @Override - public void onSuccess(File file) { - String imageToBase64 = StringHelper.imageToBase64(file); - - ImageBean imageBean = new ImageBean(); - imageBean.setImage(imageToBase64); - faceLoginPresenter.onReadyRetrofitRequest(imageBean); - } - - @Override - public void onError(Throwable e) { - // TODO 当压缩过程出现问题时调用 - } - }).launch(); + if (requestCode == Constant.FACE_DETECTOR_CODE) { + String imageToBase64 = data.getStringExtra("imageToBase64"); + ImageBean imageBean = new ImageBean(); + imageBean.setImage(imageToBase64); + faceLoginPresenter.onReadyRetrofitRequest(imageBean); } } } @@ -232,7 +195,7 @@ .setPlaySound(true)//是否扫描成功后bi~的声音 .setDingPath(R.raw.qrcode)//设置提示音(不设置为默认的Ding~) .setIsOnlyCenter(true)//是否只识别框中内容(默认为全屏识别) - .setTitleBackgroudColor(Color.parseColor("#262020"))//设置状态栏颜色 + .setTitleBackgroudColor(R.color.black)//设置状态栏颜色 .setTitleTextColor(Color.WHITE)//设置Title文字颜色 .setScreenOrientation(QrConfig.SCREEN_PORTRAIT)//设置屏幕方式 .setScanLineStyle(ScanLineView.style_hybrid)//扫描线样式 @@ -241,8 +204,8 @@ QrManager.getInstance().init(qrConfig).startScan(this, new QrManager.OnScanResultCallback() { @Override public void onScanSuccess(final ScanResult result) { -// Log.d(TAG, "扫码结果: " + result.content); - qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), result.content); + qrCode = result.content; + authenticatePresenter.onReadyRetrofitRequest();//需要时时保持最新token,所以扫码登录之前需要获取最新token } }); } @@ -254,9 +217,15 @@ @Override public void authenticateResult(PublicKeyBean result) { - Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); +// Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); if (result.isSuccess()) { PublicKey publicKey = RSAUtils.keyStrToPublicKey(result.getData().getPublicKey()); + String userName = userNameView.getText().toString(); + String userPassword = userPasswordView.getText().toString(); + if (rememberPasswordView.isChecked()) { + SaveKeyValues.putValue("userName", userName); + SaveKeyValues.putValue("userPassword", userPassword); + } if (TextUtils.isEmpty(userName)) { Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show(); return; @@ -266,7 +235,6 @@ return; } String dataByPublicKey = RSAUtils.encryptDataByPublicKey(userPassword.getBytes(), publicKey); - Log.d(TAG, "authenticateResult: 验证成功,开始登录"); //登录并获取Token,POST请求 loginPresenter.onReadyRetrofitRequest(result.getData().getSid(), userName, dataByPublicKey); } else { @@ -283,11 +251,14 @@ String token = result.getData().getToken(); if (!TextUtils.isEmpty(token)) { //获取用户信息 - Log.d(TAG, "obtainLoginResult: 获取Token成功"); TokenHelper.saveToken(token); //验证成功登录 - startActivity(new Intent(this, MainActivity.class)); - finish(); + if (isPasswordLogin) { + startActivity(new Intent(this, MainActivity.class)); + finish(); + } else { + qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), qrCode); + } } } @@ -307,15 +278,17 @@ } @Override - public void obtainFaceLoginData(FaceLoginResultBean resultBean) { -// Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); - if (resultBean.getCode() == 200) { + public void obtainFaceLoginData(FaceResultBean resultBean) { + Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); + if (resultBean.isSuccess()) { + //{"code":200,"data":{"kaptcha":"","token":"9135bcb7-4f39-4b7a-a10e-555406ddb9e1"},"exceptionClazz":"","message":"登录成功","success":true} TokenHelper.saveToken(resultBean.getData().getToken()); //验证成功登录 startActivity(new Intent(this, MainActivity.class)); finish(); } else { - Toast.makeText(this, "无法解析人脸", Toast.LENGTH_SHORT).show(); + //{"code":200,"data":"","exceptionClazz":"","message":"图片中没有人脸","success":false} + Toast.makeText(this, "人脸识别失败", Toast.LENGTH_SHORT).show(); } } @@ -336,5 +309,8 @@ if (qrCodePresenter != null) { qrCodePresenter.disposeRetrofitRequest(); } + if (faceLoginPresenter != null) { + faceLoginPresenter.disposeRetrofitRequest(); + } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java index e8e9b75..759a94d 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java @@ -9,4 +9,5 @@ Manifest.permission.WRITE_EXTERNAL_STORAGE}; public static final int PERMISSIONS_CODE = 999; + public static final int FACE_DETECTOR_CODE = 998; } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java new file mode 100644 index 0000000..b774ee9 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java @@ -0,0 +1,95 @@ +package com.casic.birmm.hxrq.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.ImageFormat; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.YuvImage; +import android.util.Base64; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class ImageHelper { + + public ImageHelper(Context context) { + + } + + public Bitmap nv21ToBitmap(byte[] nv21, int width, int height) { + Bitmap bitmap = null; + try { + final YuvImage image = new YuvImage(nv21, ImageFormat.NV21, width, height, null); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + image.compressToJpeg(new Rect(0, 0, width, height), 80, outputStream); + final Bitmap bmp = BitmapFactory.decodeByteArray(outputStream.toByteArray(), 0, outputStream.size()); + bitmap = rotateImageView(-90, bmp); + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return bitmap; + } + + public Bitmap rotateImageView(int angle, Bitmap bitmap) { + //旋转图片 动作 + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + // 创建新的图片 + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(File file) { + if (file == null) { + return null; + } + try { + FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int n; + while ((n = fis.read(b)) != -1) { + bos.write(b, 0, n); + } + fis.close(); + bos.close(); + + byte[] imgBytes = bos.toByteArray(); + String result = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (Exception e) { + return null; + } + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);//压缩质量 + + outputStream.flush(); + outputStream.close(); + + byte[] bitmapBytes = outputStream.toByteArray(); + String result = Base64.encodeToString(bitmapBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (IOException e) { + return null; + } + } +} diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java new file mode 100644 index 0000000..4109e3c --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java @@ -0,0 +1,184 @@ +package com.casic.birmm.hxrq.ui; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.NonNull; + +import com.casic.birmm.hxrq.R; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.utils.ImageHelper; + +import java.io.IOException; +import java.util.List; +import java.util.Stack; + +import butterknife.BindView; + +public class FacePreViewActivity extends BaseActivity implements Camera.PreviewCallback { + + private static final int preViewWidth = 720; + private static final int preViewHeight = 1280; + @BindView(R.id.surfaceView) + SurfaceView surfaceView; + private SurfaceHolder mSurfaceHolder; + private Camera mCamera; + private ImageHelper imageHelper; + private Stack bitmapStack; + private boolean isCanLogin = true; + + @Override + public int initLayoutView() { + return R.layout.activity_face; + } + + @Override + protected void setupTopBarLayout() { + + } + + @Override + public void initData() { + imageHelper = new ImageHelper(this); + bitmapStack = new Stack<>(); + } + + @Override + public void initEvent() { + // 绑定SurfaceView,取得SurfaceHolder对象 + mSurfaceHolder = surfaceView.getHolder(); + mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + if (mCamera == null) { + //打开相机 + openCamera(); + } + try { + //预览画面 + mCamera.setPreviewDisplay(mSurfaceHolder); + } catch (IOException e) { + e.printStackTrace(); + } + //开始预览 + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + releaseCamera(); //释放相机资源 + } + }); + mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置 + } + + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + camera.addCallbackBuffer(data); + Camera.Size size = camera.getParameters().getPreviewSize();//必须是相机支持的预览尺寸,否则颜色YUV空间会错位 + Bitmap originBitmap = imageHelper.nv21ToBitmap(data, size.width, size.height); + //要使用Android内置的人脸识别,需要将Bitmap对象转为RGB_565格式,否则无法识别 +// Bitmap faceDetectorBitmap = originBitmap.copy(Bitmap.Config.RGB_565, true); +// FaceDetector.Face[] faces = new FaceDetector.Face[1]; +// FaceDetector faceDetector = new FaceDetector(faceDetectorBitmap.getWidth(), faceDetectorBitmap.getHeight(), 1); +// int faceSum = faceDetector.findFaces(faceDetectorBitmap, faces); +// if (faceSum == 1) { + bitmapStack.push(originBitmap); + if (bitmapStack.size() >= 5) {//当栈里有5张bitmap之后才开始识别 + if (isCanLogin) { + isCanLogin = false; + Bitmap bitmap = bitmapStack.pop(); + Intent intent = new Intent(); + intent.putExtra("imageToBase64", ImageHelper.imageToBase64(bitmap)); + setResult(Activity.RESULT_OK, intent); + finish(); + } else { + finish(); + } + } +// } else { +// Log.d(TAG, "detectorFace: 未检测到人脸"); +// } + } + + /** + * 打开相机 + */ + private void openCamera() { + try { + mCamera = Camera.open(1); + initParameters(mCamera); //初始化相机配置信息 + mCamera.setPreviewCallback(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化相机属性 + */ + private void initParameters(Camera camera) { + try { + Camera.Parameters mParameters = camera.getParameters(); + mParameters.setPreviewFormat(ImageFormat.NV21); //设置预览图片的格式 + //获取与指定宽高相等或最接近的尺寸 + //设置预览尺寸 + Camera.Size bestPreviewSize = obtainBestSize(preViewWidth, preViewHeight, mParameters.getSupportedPreviewSizes()); + mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height); + //设置保存图片尺寸 +// Camera.Size bestPicSize = obtainBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes()); +// mParameters.setPictureSize(bestPicSize.width, bestPicSize.height); + //对焦模式 + mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + camera.setDisplayOrientation(90); + camera.setParameters(mParameters); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取最合适的尺寸 + */ + private Camera.Size obtainBestSize(int targetWidth, int targetHeight, List sizeList) { + Camera.Size bestSize = null; + int targetRatio = targetHeight / targetWidth;//目标大小的宽高比 + int minDiff = targetRatio; + + for (Camera.Size size : sizeList) { + if (size.width == targetHeight && size.height == targetWidth) { + bestSize = size; + break; + } + int supportedRatio = (size.width / size.height); + if (Math.abs(supportedRatio - targetRatio) < minDiff) { + minDiff = Math.abs(supportedRatio - targetRatio); + bestSize = size; + } + } + return bestSize; + } + + /** + * 释放相机资源 + */ + private void releaseCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java index 98aef9d..30c26c8 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java @@ -8,14 +8,15 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.Nullable; import com.casic.birmm.hxrq.R; -import com.casic.birmm.hxrq.base.DoubleClickExitActivity; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -28,23 +29,16 @@ import com.casic.birmm.hxrq.mvp.view.IFaceLoginView; import com.casic.birmm.hxrq.mvp.view.ILoginView; import com.casic.birmm.hxrq.mvp.view.IQrCodeDataView; -import com.casic.birmm.hxrq.utils.FileUtils; -import com.casic.birmm.hxrq.utils.GlideLoadEngine; +import com.casic.birmm.hxrq.utils.Constant; import com.casic.birmm.hxrq.utils.RSAUtils; import com.casic.birmm.hxrq.utils.SaveKeyValues; -import com.casic.birmm.hxrq.utils.StringHelper; import com.casic.birmm.hxrq.utils.TokenHelper; import com.google.gson.Gson; -import com.luck.picture.lib.PictureSelector; -import com.luck.picture.lib.config.PictureConfig; -import com.luck.picture.lib.config.PictureMimeType; -import com.luck.picture.lib.entity.LocalMedia; import com.qmuiteam.qmui.util.QMUIStatusBarHelper; import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUITipDialog; import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton; -import java.io.File; import java.security.PublicKey; import butterknife.BindView; @@ -53,15 +47,11 @@ import cn.bertsir.zbar.QrConfig; import cn.bertsir.zbar.QrManager; import cn.bertsir.zbar.view.ScanLineView; -import top.zibin.luban.CompressionPredicate; -import top.zibin.luban.Luban; -import top.zibin.luban.OnCompressListener; -public class LoginActivity extends DoubleClickExitActivity - implements View.OnClickListener, IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { +public class LoginActivity extends BaseActivity implements View.OnClickListener, + IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { private static final String TAG = "LoginActivity"; - @BindView(R.id.userNameView) EditText userNameView; @BindView(R.id.userPasswordView) @@ -76,8 +66,8 @@ private LoginPresenterImpl loginPresenter; private QrCodePresenterImpl qrCodePresenter; private FaceLoginPresenterImpl faceLoginPresenter; - private String userName; - private String userPassword; + private boolean isPasswordLogin = false; + private String qrCode = ""; @Override public int initLayoutView() { @@ -86,20 +76,29 @@ @Override protected void setupTopBarLayout() { - //TODO 此页面无需实现 + //设置状态栏黑色字体图标 + QMUIStatusBarHelper.setStatusBarLightMode(this); } @Override public void initData() { - //设置状态栏黑色字体图标 - QMUIStatusBarHelper.setStatusBarLightMode(this); - String userName = (String) SaveKeyValues.getValue("userName", ""); String userPassword = (String) SaveKeyValues.getValue("userPassword", ""); + userNameView.setText(userName); + userPasswordView.setText(userPassword); if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(userPassword)) { - userNameView.setText(userName); - userPasswordView.setText(userPassword); + rememberPasswordView.setChecked(true); + } else { + rememberPasswordView.setChecked(false); } + rememberPasswordView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!isChecked) { + SaveKeyValues.removeKey("userPassword"); + } + } + }); loadingDialog = new QMUITipDialog.Builder(this) .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING) .setTipWord("登陆中,请稍后") @@ -124,14 +123,9 @@ public void onClick(View v) { switch (v.getId()) { case R.id.loginButton: - userName = userNameView.getText().toString(); - userPassword = userPasswordView.getText().toString(); - if (rememberPasswordView.isChecked()) { - SaveKeyValues.putValue("userName", userName); - SaveKeyValues.putValue("userPassword", userPassword); - } //密码登录前需要验证sid authenticatePresenter.onReadyRetrofitRequest(); + isPasswordLogin = true; break; case R.id.changeLoginModeView: //首次登录不可用扫码,因为还未注册 @@ -169,50 +163,19 @@ } private void captureFaceData() { - //TODO 调相机,捕获人脸数据,并保存为文件得到路径 - PictureSelector.create(this) - .openCamera(PictureMimeType.ofImage()) - .imageEngine(GlideLoadEngine.createGlideEngine()) - .maxSelectNum(1) - .forResult(PictureConfig.REQUEST_CAMERA); + // 调相机,捕获人脸数据,并保存为文件得到路径 + startActivityForResult(new Intent(this, FacePreViewActivity.class), Constant.FACE_DETECTOR_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - if (requestCode == PictureConfig.REQUEST_CAMERA) { - LocalMedia localMedia = PictureSelector.obtainMultipleResult(data).get(0); - Luban.with(this) - .load(localMedia.getRealPath()) - .ignoreBy(100) - .setTargetDir(FileUtils.getFileDir("CompressImageFile")) - .filter(new CompressionPredicate() { - @Override - public boolean apply(String path) { - return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif")); - } - }) - .setCompressListener(new OnCompressListener() { - @Override - public void onStart() { - // TODO 压缩开始前调用,可以在方法内启动 loading UI - } - - @Override - public void onSuccess(File file) { - String imageToBase64 = StringHelper.imageToBase64(file); - - ImageBean imageBean = new ImageBean(); - imageBean.setImage(imageToBase64); - faceLoginPresenter.onReadyRetrofitRequest(imageBean); - } - - @Override - public void onError(Throwable e) { - // TODO 当压缩过程出现问题时调用 - } - }).launch(); + if (requestCode == Constant.FACE_DETECTOR_CODE) { + String imageToBase64 = data.getStringExtra("imageToBase64"); + ImageBean imageBean = new ImageBean(); + imageBean.setImage(imageToBase64); + faceLoginPresenter.onReadyRetrofitRequest(imageBean); } } } @@ -232,7 +195,7 @@ .setPlaySound(true)//是否扫描成功后bi~的声音 .setDingPath(R.raw.qrcode)//设置提示音(不设置为默认的Ding~) .setIsOnlyCenter(true)//是否只识别框中内容(默认为全屏识别) - .setTitleBackgroudColor(Color.parseColor("#262020"))//设置状态栏颜色 + .setTitleBackgroudColor(R.color.black)//设置状态栏颜色 .setTitleTextColor(Color.WHITE)//设置Title文字颜色 .setScreenOrientation(QrConfig.SCREEN_PORTRAIT)//设置屏幕方式 .setScanLineStyle(ScanLineView.style_hybrid)//扫描线样式 @@ -241,8 +204,8 @@ QrManager.getInstance().init(qrConfig).startScan(this, new QrManager.OnScanResultCallback() { @Override public void onScanSuccess(final ScanResult result) { -// Log.d(TAG, "扫码结果: " + result.content); - qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), result.content); + qrCode = result.content; + authenticatePresenter.onReadyRetrofitRequest();//需要时时保持最新token,所以扫码登录之前需要获取最新token } }); } @@ -254,9 +217,15 @@ @Override public void authenticateResult(PublicKeyBean result) { - Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); +// Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); if (result.isSuccess()) { PublicKey publicKey = RSAUtils.keyStrToPublicKey(result.getData().getPublicKey()); + String userName = userNameView.getText().toString(); + String userPassword = userPasswordView.getText().toString(); + if (rememberPasswordView.isChecked()) { + SaveKeyValues.putValue("userName", userName); + SaveKeyValues.putValue("userPassword", userPassword); + } if (TextUtils.isEmpty(userName)) { Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show(); return; @@ -266,7 +235,6 @@ return; } String dataByPublicKey = RSAUtils.encryptDataByPublicKey(userPassword.getBytes(), publicKey); - Log.d(TAG, "authenticateResult: 验证成功,开始登录"); //登录并获取Token,POST请求 loginPresenter.onReadyRetrofitRequest(result.getData().getSid(), userName, dataByPublicKey); } else { @@ -283,11 +251,14 @@ String token = result.getData().getToken(); if (!TextUtils.isEmpty(token)) { //获取用户信息 - Log.d(TAG, "obtainLoginResult: 获取Token成功"); TokenHelper.saveToken(token); //验证成功登录 - startActivity(new Intent(this, MainActivity.class)); - finish(); + if (isPasswordLogin) { + startActivity(new Intent(this, MainActivity.class)); + finish(); + } else { + qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), qrCode); + } } } @@ -307,15 +278,17 @@ } @Override - public void obtainFaceLoginData(FaceLoginResultBean resultBean) { -// Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); - if (resultBean.getCode() == 200) { + public void obtainFaceLoginData(FaceResultBean resultBean) { + Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); + if (resultBean.isSuccess()) { + //{"code":200,"data":{"kaptcha":"","token":"9135bcb7-4f39-4b7a-a10e-555406ddb9e1"},"exceptionClazz":"","message":"登录成功","success":true} TokenHelper.saveToken(resultBean.getData().getToken()); //验证成功登录 startActivity(new Intent(this, MainActivity.class)); finish(); } else { - Toast.makeText(this, "无法解析人脸", Toast.LENGTH_SHORT).show(); + //{"code":200,"data":"","exceptionClazz":"","message":"图片中没有人脸","success":false} + Toast.makeText(this, "人脸识别失败", Toast.LENGTH_SHORT).show(); } } @@ -336,5 +309,8 @@ if (qrCodePresenter != null) { qrCodePresenter.disposeRetrofitRequest(); } + if (faceLoginPresenter != null) { + faceLoginPresenter.disposeRetrofitRequest(); + } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java index e8e9b75..759a94d 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java @@ -9,4 +9,5 @@ Manifest.permission.WRITE_EXTERNAL_STORAGE}; public static final int PERMISSIONS_CODE = 999; + public static final int FACE_DETECTOR_CODE = 998; } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java new file mode 100644 index 0000000..b774ee9 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java @@ -0,0 +1,95 @@ +package com.casic.birmm.hxrq.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.ImageFormat; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.YuvImage; +import android.util.Base64; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class ImageHelper { + + public ImageHelper(Context context) { + + } + + public Bitmap nv21ToBitmap(byte[] nv21, int width, int height) { + Bitmap bitmap = null; + try { + final YuvImage image = new YuvImage(nv21, ImageFormat.NV21, width, height, null); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + image.compressToJpeg(new Rect(0, 0, width, height), 80, outputStream); + final Bitmap bmp = BitmapFactory.decodeByteArray(outputStream.toByteArray(), 0, outputStream.size()); + bitmap = rotateImageView(-90, bmp); + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return bitmap; + } + + public Bitmap rotateImageView(int angle, Bitmap bitmap) { + //旋转图片 动作 + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + // 创建新的图片 + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(File file) { + if (file == null) { + return null; + } + try { + FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int n; + while ((n = fis.read(b)) != -1) { + bos.write(b, 0, n); + } + fis.close(); + bos.close(); + + byte[] imgBytes = bos.toByteArray(); + String result = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (Exception e) { + return null; + } + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);//压缩质量 + + outputStream.flush(); + outputStream.close(); + + byte[] bitmapBytes = outputStream.toByteArray(); + String result = Base64.encodeToString(bitmapBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (IOException e) { + return null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java index f4af6a5..e7772dd 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java @@ -3,33 +3,26 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; -import android.util.Log; public class SaveKeyValues { - private static final String TAG = "SaveKeyValues"; - - @SuppressLint({"StaticFieldLeak"}) - private static Context context; private static SharedPreferences sharedPreferences; private static SharedPreferences.Editor editor; - private static String fileName; + @SuppressLint("CommitPrefEdits") public static void initSharedPreferences(Context mContext) { - context = mContext.getApplicationContext(); - String packageName = context.getPackageName(); + String packageName = mContext.getPackageName(); //获取到的包名带有“.”方便命名,取最后一个作为sp文件名,例如:com.casic.dcms String[] split = packageName.split("\\.");//先转义.之后才能分割 int length = split.length; - fileName = split[length - 1]; - Log.d(TAG, fileName); + String fileName = split[length - 1]; + sharedPreferences = mContext.getSharedPreferences(fileName, Context.MODE_PRIVATE); + editor = sharedPreferences.edit(); } /** * 存储 */ public static void putValue(String key, Object object) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); - editor = sharedPreferences.edit(); if (object instanceof String) { editor.putString(key, (String) object); } else if (object instanceof Integer) { @@ -50,7 +43,6 @@ * 获取保存的数据 */ public static Object getValue(String key, Object defaultObject) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); if (defaultObject instanceof String) { return sharedPreferences.getString(key, (String) defaultObject); } else if (defaultObject instanceof Integer) { @@ -86,7 +78,6 @@ * 查询某个key是否存在 */ public static boolean containsKey(String key) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); return sharedPreferences.contains(key); } } diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java new file mode 100644 index 0000000..4109e3c --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java @@ -0,0 +1,184 @@ +package com.casic.birmm.hxrq.ui; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.NonNull; + +import com.casic.birmm.hxrq.R; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.utils.ImageHelper; + +import java.io.IOException; +import java.util.List; +import java.util.Stack; + +import butterknife.BindView; + +public class FacePreViewActivity extends BaseActivity implements Camera.PreviewCallback { + + private static final int preViewWidth = 720; + private static final int preViewHeight = 1280; + @BindView(R.id.surfaceView) + SurfaceView surfaceView; + private SurfaceHolder mSurfaceHolder; + private Camera mCamera; + private ImageHelper imageHelper; + private Stack bitmapStack; + private boolean isCanLogin = true; + + @Override + public int initLayoutView() { + return R.layout.activity_face; + } + + @Override + protected void setupTopBarLayout() { + + } + + @Override + public void initData() { + imageHelper = new ImageHelper(this); + bitmapStack = new Stack<>(); + } + + @Override + public void initEvent() { + // 绑定SurfaceView,取得SurfaceHolder对象 + mSurfaceHolder = surfaceView.getHolder(); + mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + if (mCamera == null) { + //打开相机 + openCamera(); + } + try { + //预览画面 + mCamera.setPreviewDisplay(mSurfaceHolder); + } catch (IOException e) { + e.printStackTrace(); + } + //开始预览 + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + releaseCamera(); //释放相机资源 + } + }); + mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置 + } + + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + camera.addCallbackBuffer(data); + Camera.Size size = camera.getParameters().getPreviewSize();//必须是相机支持的预览尺寸,否则颜色YUV空间会错位 + Bitmap originBitmap = imageHelper.nv21ToBitmap(data, size.width, size.height); + //要使用Android内置的人脸识别,需要将Bitmap对象转为RGB_565格式,否则无法识别 +// Bitmap faceDetectorBitmap = originBitmap.copy(Bitmap.Config.RGB_565, true); +// FaceDetector.Face[] faces = new FaceDetector.Face[1]; +// FaceDetector faceDetector = new FaceDetector(faceDetectorBitmap.getWidth(), faceDetectorBitmap.getHeight(), 1); +// int faceSum = faceDetector.findFaces(faceDetectorBitmap, faces); +// if (faceSum == 1) { + bitmapStack.push(originBitmap); + if (bitmapStack.size() >= 5) {//当栈里有5张bitmap之后才开始识别 + if (isCanLogin) { + isCanLogin = false; + Bitmap bitmap = bitmapStack.pop(); + Intent intent = new Intent(); + intent.putExtra("imageToBase64", ImageHelper.imageToBase64(bitmap)); + setResult(Activity.RESULT_OK, intent); + finish(); + } else { + finish(); + } + } +// } else { +// Log.d(TAG, "detectorFace: 未检测到人脸"); +// } + } + + /** + * 打开相机 + */ + private void openCamera() { + try { + mCamera = Camera.open(1); + initParameters(mCamera); //初始化相机配置信息 + mCamera.setPreviewCallback(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化相机属性 + */ + private void initParameters(Camera camera) { + try { + Camera.Parameters mParameters = camera.getParameters(); + mParameters.setPreviewFormat(ImageFormat.NV21); //设置预览图片的格式 + //获取与指定宽高相等或最接近的尺寸 + //设置预览尺寸 + Camera.Size bestPreviewSize = obtainBestSize(preViewWidth, preViewHeight, mParameters.getSupportedPreviewSizes()); + mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height); + //设置保存图片尺寸 +// Camera.Size bestPicSize = obtainBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes()); +// mParameters.setPictureSize(bestPicSize.width, bestPicSize.height); + //对焦模式 + mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + camera.setDisplayOrientation(90); + camera.setParameters(mParameters); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取最合适的尺寸 + */ + private Camera.Size obtainBestSize(int targetWidth, int targetHeight, List sizeList) { + Camera.Size bestSize = null; + int targetRatio = targetHeight / targetWidth;//目标大小的宽高比 + int minDiff = targetRatio; + + for (Camera.Size size : sizeList) { + if (size.width == targetHeight && size.height == targetWidth) { + bestSize = size; + break; + } + int supportedRatio = (size.width / size.height); + if (Math.abs(supportedRatio - targetRatio) < minDiff) { + minDiff = Math.abs(supportedRatio - targetRatio); + bestSize = size; + } + } + return bestSize; + } + + /** + * 释放相机资源 + */ + private void releaseCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java index 98aef9d..30c26c8 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java @@ -8,14 +8,15 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.Nullable; import com.casic.birmm.hxrq.R; -import com.casic.birmm.hxrq.base.DoubleClickExitActivity; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -28,23 +29,16 @@ import com.casic.birmm.hxrq.mvp.view.IFaceLoginView; import com.casic.birmm.hxrq.mvp.view.ILoginView; import com.casic.birmm.hxrq.mvp.view.IQrCodeDataView; -import com.casic.birmm.hxrq.utils.FileUtils; -import com.casic.birmm.hxrq.utils.GlideLoadEngine; +import com.casic.birmm.hxrq.utils.Constant; import com.casic.birmm.hxrq.utils.RSAUtils; import com.casic.birmm.hxrq.utils.SaveKeyValues; -import com.casic.birmm.hxrq.utils.StringHelper; import com.casic.birmm.hxrq.utils.TokenHelper; import com.google.gson.Gson; -import com.luck.picture.lib.PictureSelector; -import com.luck.picture.lib.config.PictureConfig; -import com.luck.picture.lib.config.PictureMimeType; -import com.luck.picture.lib.entity.LocalMedia; import com.qmuiteam.qmui.util.QMUIStatusBarHelper; import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUITipDialog; import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton; -import java.io.File; import java.security.PublicKey; import butterknife.BindView; @@ -53,15 +47,11 @@ import cn.bertsir.zbar.QrConfig; import cn.bertsir.zbar.QrManager; import cn.bertsir.zbar.view.ScanLineView; -import top.zibin.luban.CompressionPredicate; -import top.zibin.luban.Luban; -import top.zibin.luban.OnCompressListener; -public class LoginActivity extends DoubleClickExitActivity - implements View.OnClickListener, IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { +public class LoginActivity extends BaseActivity implements View.OnClickListener, + IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { private static final String TAG = "LoginActivity"; - @BindView(R.id.userNameView) EditText userNameView; @BindView(R.id.userPasswordView) @@ -76,8 +66,8 @@ private LoginPresenterImpl loginPresenter; private QrCodePresenterImpl qrCodePresenter; private FaceLoginPresenterImpl faceLoginPresenter; - private String userName; - private String userPassword; + private boolean isPasswordLogin = false; + private String qrCode = ""; @Override public int initLayoutView() { @@ -86,20 +76,29 @@ @Override protected void setupTopBarLayout() { - //TODO 此页面无需实现 + //设置状态栏黑色字体图标 + QMUIStatusBarHelper.setStatusBarLightMode(this); } @Override public void initData() { - //设置状态栏黑色字体图标 - QMUIStatusBarHelper.setStatusBarLightMode(this); - String userName = (String) SaveKeyValues.getValue("userName", ""); String userPassword = (String) SaveKeyValues.getValue("userPassword", ""); + userNameView.setText(userName); + userPasswordView.setText(userPassword); if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(userPassword)) { - userNameView.setText(userName); - userPasswordView.setText(userPassword); + rememberPasswordView.setChecked(true); + } else { + rememberPasswordView.setChecked(false); } + rememberPasswordView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!isChecked) { + SaveKeyValues.removeKey("userPassword"); + } + } + }); loadingDialog = new QMUITipDialog.Builder(this) .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING) .setTipWord("登陆中,请稍后") @@ -124,14 +123,9 @@ public void onClick(View v) { switch (v.getId()) { case R.id.loginButton: - userName = userNameView.getText().toString(); - userPassword = userPasswordView.getText().toString(); - if (rememberPasswordView.isChecked()) { - SaveKeyValues.putValue("userName", userName); - SaveKeyValues.putValue("userPassword", userPassword); - } //密码登录前需要验证sid authenticatePresenter.onReadyRetrofitRequest(); + isPasswordLogin = true; break; case R.id.changeLoginModeView: //首次登录不可用扫码,因为还未注册 @@ -169,50 +163,19 @@ } private void captureFaceData() { - //TODO 调相机,捕获人脸数据,并保存为文件得到路径 - PictureSelector.create(this) - .openCamera(PictureMimeType.ofImage()) - .imageEngine(GlideLoadEngine.createGlideEngine()) - .maxSelectNum(1) - .forResult(PictureConfig.REQUEST_CAMERA); + // 调相机,捕获人脸数据,并保存为文件得到路径 + startActivityForResult(new Intent(this, FacePreViewActivity.class), Constant.FACE_DETECTOR_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - if (requestCode == PictureConfig.REQUEST_CAMERA) { - LocalMedia localMedia = PictureSelector.obtainMultipleResult(data).get(0); - Luban.with(this) - .load(localMedia.getRealPath()) - .ignoreBy(100) - .setTargetDir(FileUtils.getFileDir("CompressImageFile")) - .filter(new CompressionPredicate() { - @Override - public boolean apply(String path) { - return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif")); - } - }) - .setCompressListener(new OnCompressListener() { - @Override - public void onStart() { - // TODO 压缩开始前调用,可以在方法内启动 loading UI - } - - @Override - public void onSuccess(File file) { - String imageToBase64 = StringHelper.imageToBase64(file); - - ImageBean imageBean = new ImageBean(); - imageBean.setImage(imageToBase64); - faceLoginPresenter.onReadyRetrofitRequest(imageBean); - } - - @Override - public void onError(Throwable e) { - // TODO 当压缩过程出现问题时调用 - } - }).launch(); + if (requestCode == Constant.FACE_DETECTOR_CODE) { + String imageToBase64 = data.getStringExtra("imageToBase64"); + ImageBean imageBean = new ImageBean(); + imageBean.setImage(imageToBase64); + faceLoginPresenter.onReadyRetrofitRequest(imageBean); } } } @@ -232,7 +195,7 @@ .setPlaySound(true)//是否扫描成功后bi~的声音 .setDingPath(R.raw.qrcode)//设置提示音(不设置为默认的Ding~) .setIsOnlyCenter(true)//是否只识别框中内容(默认为全屏识别) - .setTitleBackgroudColor(Color.parseColor("#262020"))//设置状态栏颜色 + .setTitleBackgroudColor(R.color.black)//设置状态栏颜色 .setTitleTextColor(Color.WHITE)//设置Title文字颜色 .setScreenOrientation(QrConfig.SCREEN_PORTRAIT)//设置屏幕方式 .setScanLineStyle(ScanLineView.style_hybrid)//扫描线样式 @@ -241,8 +204,8 @@ QrManager.getInstance().init(qrConfig).startScan(this, new QrManager.OnScanResultCallback() { @Override public void onScanSuccess(final ScanResult result) { -// Log.d(TAG, "扫码结果: " + result.content); - qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), result.content); + qrCode = result.content; + authenticatePresenter.onReadyRetrofitRequest();//需要时时保持最新token,所以扫码登录之前需要获取最新token } }); } @@ -254,9 +217,15 @@ @Override public void authenticateResult(PublicKeyBean result) { - Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); +// Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); if (result.isSuccess()) { PublicKey publicKey = RSAUtils.keyStrToPublicKey(result.getData().getPublicKey()); + String userName = userNameView.getText().toString(); + String userPassword = userPasswordView.getText().toString(); + if (rememberPasswordView.isChecked()) { + SaveKeyValues.putValue("userName", userName); + SaveKeyValues.putValue("userPassword", userPassword); + } if (TextUtils.isEmpty(userName)) { Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show(); return; @@ -266,7 +235,6 @@ return; } String dataByPublicKey = RSAUtils.encryptDataByPublicKey(userPassword.getBytes(), publicKey); - Log.d(TAG, "authenticateResult: 验证成功,开始登录"); //登录并获取Token,POST请求 loginPresenter.onReadyRetrofitRequest(result.getData().getSid(), userName, dataByPublicKey); } else { @@ -283,11 +251,14 @@ String token = result.getData().getToken(); if (!TextUtils.isEmpty(token)) { //获取用户信息 - Log.d(TAG, "obtainLoginResult: 获取Token成功"); TokenHelper.saveToken(token); //验证成功登录 - startActivity(new Intent(this, MainActivity.class)); - finish(); + if (isPasswordLogin) { + startActivity(new Intent(this, MainActivity.class)); + finish(); + } else { + qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), qrCode); + } } } @@ -307,15 +278,17 @@ } @Override - public void obtainFaceLoginData(FaceLoginResultBean resultBean) { -// Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); - if (resultBean.getCode() == 200) { + public void obtainFaceLoginData(FaceResultBean resultBean) { + Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); + if (resultBean.isSuccess()) { + //{"code":200,"data":{"kaptcha":"","token":"9135bcb7-4f39-4b7a-a10e-555406ddb9e1"},"exceptionClazz":"","message":"登录成功","success":true} TokenHelper.saveToken(resultBean.getData().getToken()); //验证成功登录 startActivity(new Intent(this, MainActivity.class)); finish(); } else { - Toast.makeText(this, "无法解析人脸", Toast.LENGTH_SHORT).show(); + //{"code":200,"data":"","exceptionClazz":"","message":"图片中没有人脸","success":false} + Toast.makeText(this, "人脸识别失败", Toast.LENGTH_SHORT).show(); } } @@ -336,5 +309,8 @@ if (qrCodePresenter != null) { qrCodePresenter.disposeRetrofitRequest(); } + if (faceLoginPresenter != null) { + faceLoginPresenter.disposeRetrofitRequest(); + } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java index e8e9b75..759a94d 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java @@ -9,4 +9,5 @@ Manifest.permission.WRITE_EXTERNAL_STORAGE}; public static final int PERMISSIONS_CODE = 999; + public static final int FACE_DETECTOR_CODE = 998; } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java new file mode 100644 index 0000000..b774ee9 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java @@ -0,0 +1,95 @@ +package com.casic.birmm.hxrq.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.ImageFormat; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.YuvImage; +import android.util.Base64; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class ImageHelper { + + public ImageHelper(Context context) { + + } + + public Bitmap nv21ToBitmap(byte[] nv21, int width, int height) { + Bitmap bitmap = null; + try { + final YuvImage image = new YuvImage(nv21, ImageFormat.NV21, width, height, null); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + image.compressToJpeg(new Rect(0, 0, width, height), 80, outputStream); + final Bitmap bmp = BitmapFactory.decodeByteArray(outputStream.toByteArray(), 0, outputStream.size()); + bitmap = rotateImageView(-90, bmp); + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return bitmap; + } + + public Bitmap rotateImageView(int angle, Bitmap bitmap) { + //旋转图片 动作 + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + // 创建新的图片 + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(File file) { + if (file == null) { + return null; + } + try { + FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int n; + while ((n = fis.read(b)) != -1) { + bos.write(b, 0, n); + } + fis.close(); + bos.close(); + + byte[] imgBytes = bos.toByteArray(); + String result = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (Exception e) { + return null; + } + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);//压缩质量 + + outputStream.flush(); + outputStream.close(); + + byte[] bitmapBytes = outputStream.toByteArray(); + String result = Base64.encodeToString(bitmapBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (IOException e) { + return null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java index f4af6a5..e7772dd 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java @@ -3,33 +3,26 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; -import android.util.Log; public class SaveKeyValues { - private static final String TAG = "SaveKeyValues"; - - @SuppressLint({"StaticFieldLeak"}) - private static Context context; private static SharedPreferences sharedPreferences; private static SharedPreferences.Editor editor; - private static String fileName; + @SuppressLint("CommitPrefEdits") public static void initSharedPreferences(Context mContext) { - context = mContext.getApplicationContext(); - String packageName = context.getPackageName(); + String packageName = mContext.getPackageName(); //获取到的包名带有“.”方便命名,取最后一个作为sp文件名,例如:com.casic.dcms String[] split = packageName.split("\\.");//先转义.之后才能分割 int length = split.length; - fileName = split[length - 1]; - Log.d(TAG, fileName); + String fileName = split[length - 1]; + sharedPreferences = mContext.getSharedPreferences(fileName, Context.MODE_PRIVATE); + editor = sharedPreferences.edit(); } /** * 存储 */ public static void putValue(String key, Object object) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); - editor = sharedPreferences.edit(); if (object instanceof String) { editor.putString(key, (String) object); } else if (object instanceof Integer) { @@ -50,7 +43,6 @@ * 获取保存的数据 */ public static Object getValue(String key, Object defaultObject) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); if (defaultObject instanceof String) { return sharedPreferences.getString(key, (String) defaultObject); } else if (defaultObject instanceof Integer) { @@ -86,7 +78,6 @@ * 查询某个key是否存在 */ public static boolean containsKey(String key) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); return sharedPreferences.contains(key); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java deleted file mode 100644 index 0ebf16a..0000000 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.casic.birmm.hxrq.utils; - -import android.util.Base64; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; - -/** - * @Author: Pengxh - * @Time: 2021/4/9 15:12 - * @Email: 290677893@qq.com - **/ -public class StringHelper { - /** - * 获取图片base64编码 - */ - public static String imageToBase64(File file) { - if (file == null) { - return null; - } - try { - FileInputStream fis = new FileInputStream(file); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] b = new byte[1024]; - int n; - while ((n = fis.read(b)) != -1) { - bos.write(b, 0, n); - } - fis.close(); - bos.close(); - - byte[] imgBytes = bos.toByteArray(); - String s = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); - return s.replace("-", "+") - .replace("_", "/"); - } catch (Exception e) { - return null; - } - } -} diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java new file mode 100644 index 0000000..4109e3c --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java @@ -0,0 +1,184 @@ +package com.casic.birmm.hxrq.ui; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.NonNull; + +import com.casic.birmm.hxrq.R; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.utils.ImageHelper; + +import java.io.IOException; +import java.util.List; +import java.util.Stack; + +import butterknife.BindView; + +public class FacePreViewActivity extends BaseActivity implements Camera.PreviewCallback { + + private static final int preViewWidth = 720; + private static final int preViewHeight = 1280; + @BindView(R.id.surfaceView) + SurfaceView surfaceView; + private SurfaceHolder mSurfaceHolder; + private Camera mCamera; + private ImageHelper imageHelper; + private Stack bitmapStack; + private boolean isCanLogin = true; + + @Override + public int initLayoutView() { + return R.layout.activity_face; + } + + @Override + protected void setupTopBarLayout() { + + } + + @Override + public void initData() { + imageHelper = new ImageHelper(this); + bitmapStack = new Stack<>(); + } + + @Override + public void initEvent() { + // 绑定SurfaceView,取得SurfaceHolder对象 + mSurfaceHolder = surfaceView.getHolder(); + mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + if (mCamera == null) { + //打开相机 + openCamera(); + } + try { + //预览画面 + mCamera.setPreviewDisplay(mSurfaceHolder); + } catch (IOException e) { + e.printStackTrace(); + } + //开始预览 + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + releaseCamera(); //释放相机资源 + } + }); + mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置 + } + + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + camera.addCallbackBuffer(data); + Camera.Size size = camera.getParameters().getPreviewSize();//必须是相机支持的预览尺寸,否则颜色YUV空间会错位 + Bitmap originBitmap = imageHelper.nv21ToBitmap(data, size.width, size.height); + //要使用Android内置的人脸识别,需要将Bitmap对象转为RGB_565格式,否则无法识别 +// Bitmap faceDetectorBitmap = originBitmap.copy(Bitmap.Config.RGB_565, true); +// FaceDetector.Face[] faces = new FaceDetector.Face[1]; +// FaceDetector faceDetector = new FaceDetector(faceDetectorBitmap.getWidth(), faceDetectorBitmap.getHeight(), 1); +// int faceSum = faceDetector.findFaces(faceDetectorBitmap, faces); +// if (faceSum == 1) { + bitmapStack.push(originBitmap); + if (bitmapStack.size() >= 5) {//当栈里有5张bitmap之后才开始识别 + if (isCanLogin) { + isCanLogin = false; + Bitmap bitmap = bitmapStack.pop(); + Intent intent = new Intent(); + intent.putExtra("imageToBase64", ImageHelper.imageToBase64(bitmap)); + setResult(Activity.RESULT_OK, intent); + finish(); + } else { + finish(); + } + } +// } else { +// Log.d(TAG, "detectorFace: 未检测到人脸"); +// } + } + + /** + * 打开相机 + */ + private void openCamera() { + try { + mCamera = Camera.open(1); + initParameters(mCamera); //初始化相机配置信息 + mCamera.setPreviewCallback(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化相机属性 + */ + private void initParameters(Camera camera) { + try { + Camera.Parameters mParameters = camera.getParameters(); + mParameters.setPreviewFormat(ImageFormat.NV21); //设置预览图片的格式 + //获取与指定宽高相等或最接近的尺寸 + //设置预览尺寸 + Camera.Size bestPreviewSize = obtainBestSize(preViewWidth, preViewHeight, mParameters.getSupportedPreviewSizes()); + mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height); + //设置保存图片尺寸 +// Camera.Size bestPicSize = obtainBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes()); +// mParameters.setPictureSize(bestPicSize.width, bestPicSize.height); + //对焦模式 + mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + camera.setDisplayOrientation(90); + camera.setParameters(mParameters); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取最合适的尺寸 + */ + private Camera.Size obtainBestSize(int targetWidth, int targetHeight, List sizeList) { + Camera.Size bestSize = null; + int targetRatio = targetHeight / targetWidth;//目标大小的宽高比 + int minDiff = targetRatio; + + for (Camera.Size size : sizeList) { + if (size.width == targetHeight && size.height == targetWidth) { + bestSize = size; + break; + } + int supportedRatio = (size.width / size.height); + if (Math.abs(supportedRatio - targetRatio) < minDiff) { + minDiff = Math.abs(supportedRatio - targetRatio); + bestSize = size; + } + } + return bestSize; + } + + /** + * 释放相机资源 + */ + private void releaseCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java index 98aef9d..30c26c8 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java @@ -8,14 +8,15 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.Nullable; import com.casic.birmm.hxrq.R; -import com.casic.birmm.hxrq.base.DoubleClickExitActivity; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -28,23 +29,16 @@ import com.casic.birmm.hxrq.mvp.view.IFaceLoginView; import com.casic.birmm.hxrq.mvp.view.ILoginView; import com.casic.birmm.hxrq.mvp.view.IQrCodeDataView; -import com.casic.birmm.hxrq.utils.FileUtils; -import com.casic.birmm.hxrq.utils.GlideLoadEngine; +import com.casic.birmm.hxrq.utils.Constant; import com.casic.birmm.hxrq.utils.RSAUtils; import com.casic.birmm.hxrq.utils.SaveKeyValues; -import com.casic.birmm.hxrq.utils.StringHelper; import com.casic.birmm.hxrq.utils.TokenHelper; import com.google.gson.Gson; -import com.luck.picture.lib.PictureSelector; -import com.luck.picture.lib.config.PictureConfig; -import com.luck.picture.lib.config.PictureMimeType; -import com.luck.picture.lib.entity.LocalMedia; import com.qmuiteam.qmui.util.QMUIStatusBarHelper; import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUITipDialog; import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton; -import java.io.File; import java.security.PublicKey; import butterknife.BindView; @@ -53,15 +47,11 @@ import cn.bertsir.zbar.QrConfig; import cn.bertsir.zbar.QrManager; import cn.bertsir.zbar.view.ScanLineView; -import top.zibin.luban.CompressionPredicate; -import top.zibin.luban.Luban; -import top.zibin.luban.OnCompressListener; -public class LoginActivity extends DoubleClickExitActivity - implements View.OnClickListener, IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { +public class LoginActivity extends BaseActivity implements View.OnClickListener, + IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { private static final String TAG = "LoginActivity"; - @BindView(R.id.userNameView) EditText userNameView; @BindView(R.id.userPasswordView) @@ -76,8 +66,8 @@ private LoginPresenterImpl loginPresenter; private QrCodePresenterImpl qrCodePresenter; private FaceLoginPresenterImpl faceLoginPresenter; - private String userName; - private String userPassword; + private boolean isPasswordLogin = false; + private String qrCode = ""; @Override public int initLayoutView() { @@ -86,20 +76,29 @@ @Override protected void setupTopBarLayout() { - //TODO 此页面无需实现 + //设置状态栏黑色字体图标 + QMUIStatusBarHelper.setStatusBarLightMode(this); } @Override public void initData() { - //设置状态栏黑色字体图标 - QMUIStatusBarHelper.setStatusBarLightMode(this); - String userName = (String) SaveKeyValues.getValue("userName", ""); String userPassword = (String) SaveKeyValues.getValue("userPassword", ""); + userNameView.setText(userName); + userPasswordView.setText(userPassword); if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(userPassword)) { - userNameView.setText(userName); - userPasswordView.setText(userPassword); + rememberPasswordView.setChecked(true); + } else { + rememberPasswordView.setChecked(false); } + rememberPasswordView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!isChecked) { + SaveKeyValues.removeKey("userPassword"); + } + } + }); loadingDialog = new QMUITipDialog.Builder(this) .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING) .setTipWord("登陆中,请稍后") @@ -124,14 +123,9 @@ public void onClick(View v) { switch (v.getId()) { case R.id.loginButton: - userName = userNameView.getText().toString(); - userPassword = userPasswordView.getText().toString(); - if (rememberPasswordView.isChecked()) { - SaveKeyValues.putValue("userName", userName); - SaveKeyValues.putValue("userPassword", userPassword); - } //密码登录前需要验证sid authenticatePresenter.onReadyRetrofitRequest(); + isPasswordLogin = true; break; case R.id.changeLoginModeView: //首次登录不可用扫码,因为还未注册 @@ -169,50 +163,19 @@ } private void captureFaceData() { - //TODO 调相机,捕获人脸数据,并保存为文件得到路径 - PictureSelector.create(this) - .openCamera(PictureMimeType.ofImage()) - .imageEngine(GlideLoadEngine.createGlideEngine()) - .maxSelectNum(1) - .forResult(PictureConfig.REQUEST_CAMERA); + // 调相机,捕获人脸数据,并保存为文件得到路径 + startActivityForResult(new Intent(this, FacePreViewActivity.class), Constant.FACE_DETECTOR_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - if (requestCode == PictureConfig.REQUEST_CAMERA) { - LocalMedia localMedia = PictureSelector.obtainMultipleResult(data).get(0); - Luban.with(this) - .load(localMedia.getRealPath()) - .ignoreBy(100) - .setTargetDir(FileUtils.getFileDir("CompressImageFile")) - .filter(new CompressionPredicate() { - @Override - public boolean apply(String path) { - return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif")); - } - }) - .setCompressListener(new OnCompressListener() { - @Override - public void onStart() { - // TODO 压缩开始前调用,可以在方法内启动 loading UI - } - - @Override - public void onSuccess(File file) { - String imageToBase64 = StringHelper.imageToBase64(file); - - ImageBean imageBean = new ImageBean(); - imageBean.setImage(imageToBase64); - faceLoginPresenter.onReadyRetrofitRequest(imageBean); - } - - @Override - public void onError(Throwable e) { - // TODO 当压缩过程出现问题时调用 - } - }).launch(); + if (requestCode == Constant.FACE_DETECTOR_CODE) { + String imageToBase64 = data.getStringExtra("imageToBase64"); + ImageBean imageBean = new ImageBean(); + imageBean.setImage(imageToBase64); + faceLoginPresenter.onReadyRetrofitRequest(imageBean); } } } @@ -232,7 +195,7 @@ .setPlaySound(true)//是否扫描成功后bi~的声音 .setDingPath(R.raw.qrcode)//设置提示音(不设置为默认的Ding~) .setIsOnlyCenter(true)//是否只识别框中内容(默认为全屏识别) - .setTitleBackgroudColor(Color.parseColor("#262020"))//设置状态栏颜色 + .setTitleBackgroudColor(R.color.black)//设置状态栏颜色 .setTitleTextColor(Color.WHITE)//设置Title文字颜色 .setScreenOrientation(QrConfig.SCREEN_PORTRAIT)//设置屏幕方式 .setScanLineStyle(ScanLineView.style_hybrid)//扫描线样式 @@ -241,8 +204,8 @@ QrManager.getInstance().init(qrConfig).startScan(this, new QrManager.OnScanResultCallback() { @Override public void onScanSuccess(final ScanResult result) { -// Log.d(TAG, "扫码结果: " + result.content); - qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), result.content); + qrCode = result.content; + authenticatePresenter.onReadyRetrofitRequest();//需要时时保持最新token,所以扫码登录之前需要获取最新token } }); } @@ -254,9 +217,15 @@ @Override public void authenticateResult(PublicKeyBean result) { - Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); +// Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); if (result.isSuccess()) { PublicKey publicKey = RSAUtils.keyStrToPublicKey(result.getData().getPublicKey()); + String userName = userNameView.getText().toString(); + String userPassword = userPasswordView.getText().toString(); + if (rememberPasswordView.isChecked()) { + SaveKeyValues.putValue("userName", userName); + SaveKeyValues.putValue("userPassword", userPassword); + } if (TextUtils.isEmpty(userName)) { Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show(); return; @@ -266,7 +235,6 @@ return; } String dataByPublicKey = RSAUtils.encryptDataByPublicKey(userPassword.getBytes(), publicKey); - Log.d(TAG, "authenticateResult: 验证成功,开始登录"); //登录并获取Token,POST请求 loginPresenter.onReadyRetrofitRequest(result.getData().getSid(), userName, dataByPublicKey); } else { @@ -283,11 +251,14 @@ String token = result.getData().getToken(); if (!TextUtils.isEmpty(token)) { //获取用户信息 - Log.d(TAG, "obtainLoginResult: 获取Token成功"); TokenHelper.saveToken(token); //验证成功登录 - startActivity(new Intent(this, MainActivity.class)); - finish(); + if (isPasswordLogin) { + startActivity(new Intent(this, MainActivity.class)); + finish(); + } else { + qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), qrCode); + } } } @@ -307,15 +278,17 @@ } @Override - public void obtainFaceLoginData(FaceLoginResultBean resultBean) { -// Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); - if (resultBean.getCode() == 200) { + public void obtainFaceLoginData(FaceResultBean resultBean) { + Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); + if (resultBean.isSuccess()) { + //{"code":200,"data":{"kaptcha":"","token":"9135bcb7-4f39-4b7a-a10e-555406ddb9e1"},"exceptionClazz":"","message":"登录成功","success":true} TokenHelper.saveToken(resultBean.getData().getToken()); //验证成功登录 startActivity(new Intent(this, MainActivity.class)); finish(); } else { - Toast.makeText(this, "无法解析人脸", Toast.LENGTH_SHORT).show(); + //{"code":200,"data":"","exceptionClazz":"","message":"图片中没有人脸","success":false} + Toast.makeText(this, "人脸识别失败", Toast.LENGTH_SHORT).show(); } } @@ -336,5 +309,8 @@ if (qrCodePresenter != null) { qrCodePresenter.disposeRetrofitRequest(); } + if (faceLoginPresenter != null) { + faceLoginPresenter.disposeRetrofitRequest(); + } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java index e8e9b75..759a94d 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java @@ -9,4 +9,5 @@ Manifest.permission.WRITE_EXTERNAL_STORAGE}; public static final int PERMISSIONS_CODE = 999; + public static final int FACE_DETECTOR_CODE = 998; } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java new file mode 100644 index 0000000..b774ee9 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java @@ -0,0 +1,95 @@ +package com.casic.birmm.hxrq.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.ImageFormat; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.YuvImage; +import android.util.Base64; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class ImageHelper { + + public ImageHelper(Context context) { + + } + + public Bitmap nv21ToBitmap(byte[] nv21, int width, int height) { + Bitmap bitmap = null; + try { + final YuvImage image = new YuvImage(nv21, ImageFormat.NV21, width, height, null); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + image.compressToJpeg(new Rect(0, 0, width, height), 80, outputStream); + final Bitmap bmp = BitmapFactory.decodeByteArray(outputStream.toByteArray(), 0, outputStream.size()); + bitmap = rotateImageView(-90, bmp); + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return bitmap; + } + + public Bitmap rotateImageView(int angle, Bitmap bitmap) { + //旋转图片 动作 + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + // 创建新的图片 + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(File file) { + if (file == null) { + return null; + } + try { + FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int n; + while ((n = fis.read(b)) != -1) { + bos.write(b, 0, n); + } + fis.close(); + bos.close(); + + byte[] imgBytes = bos.toByteArray(); + String result = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (Exception e) { + return null; + } + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);//压缩质量 + + outputStream.flush(); + outputStream.close(); + + byte[] bitmapBytes = outputStream.toByteArray(); + String result = Base64.encodeToString(bitmapBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (IOException e) { + return null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java index f4af6a5..e7772dd 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java @@ -3,33 +3,26 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; -import android.util.Log; public class SaveKeyValues { - private static final String TAG = "SaveKeyValues"; - - @SuppressLint({"StaticFieldLeak"}) - private static Context context; private static SharedPreferences sharedPreferences; private static SharedPreferences.Editor editor; - private static String fileName; + @SuppressLint("CommitPrefEdits") public static void initSharedPreferences(Context mContext) { - context = mContext.getApplicationContext(); - String packageName = context.getPackageName(); + String packageName = mContext.getPackageName(); //获取到的包名带有“.”方便命名,取最后一个作为sp文件名,例如:com.casic.dcms String[] split = packageName.split("\\.");//先转义.之后才能分割 int length = split.length; - fileName = split[length - 1]; - Log.d(TAG, fileName); + String fileName = split[length - 1]; + sharedPreferences = mContext.getSharedPreferences(fileName, Context.MODE_PRIVATE); + editor = sharedPreferences.edit(); } /** * 存储 */ public static void putValue(String key, Object object) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); - editor = sharedPreferences.edit(); if (object instanceof String) { editor.putString(key, (String) object); } else if (object instanceof Integer) { @@ -50,7 +43,6 @@ * 获取保存的数据 */ public static Object getValue(String key, Object defaultObject) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); if (defaultObject instanceof String) { return sharedPreferences.getString(key, (String) defaultObject); } else if (defaultObject instanceof Integer) { @@ -86,7 +78,6 @@ * 查询某个key是否存在 */ public static boolean containsKey(String key) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); return sharedPreferences.contains(key); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java deleted file mode 100644 index 0ebf16a..0000000 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.casic.birmm.hxrq.utils; - -import android.util.Base64; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; - -/** - * @Author: Pengxh - * @Time: 2021/4/9 15:12 - * @Email: 290677893@qq.com - **/ -public class StringHelper { - /** - * 获取图片base64编码 - */ - public static String imageToBase64(File file) { - if (file == null) { - return null; - } - try { - FileInputStream fis = new FileInputStream(file); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] b = new byte[1024]; - int n; - while ((n = fis.read(b)) != -1) { - bos.write(b, 0, n); - } - fis.close(); - bos.close(); - - byte[] imgBytes = bos.toByteArray(); - String s = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); - return s.replace("-", "+") - .replace("_", "/"); - } catch (Exception e) { - return null; - } - } -} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java index 8fe5264..1de1ff4 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.utils.retrofit; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -49,6 +49,6 @@ */ @Headers({"Content-Type: application/json"}) @POST("/cockpit/face/login") - Observable getFaceLoginResult( + Observable getFaceLoginResult( @Body ImageBean imageBean); } diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java new file mode 100644 index 0000000..4109e3c --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java @@ -0,0 +1,184 @@ +package com.casic.birmm.hxrq.ui; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.NonNull; + +import com.casic.birmm.hxrq.R; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.utils.ImageHelper; + +import java.io.IOException; +import java.util.List; +import java.util.Stack; + +import butterknife.BindView; + +public class FacePreViewActivity extends BaseActivity implements Camera.PreviewCallback { + + private static final int preViewWidth = 720; + private static final int preViewHeight = 1280; + @BindView(R.id.surfaceView) + SurfaceView surfaceView; + private SurfaceHolder mSurfaceHolder; + private Camera mCamera; + private ImageHelper imageHelper; + private Stack bitmapStack; + private boolean isCanLogin = true; + + @Override + public int initLayoutView() { + return R.layout.activity_face; + } + + @Override + protected void setupTopBarLayout() { + + } + + @Override + public void initData() { + imageHelper = new ImageHelper(this); + bitmapStack = new Stack<>(); + } + + @Override + public void initEvent() { + // 绑定SurfaceView,取得SurfaceHolder对象 + mSurfaceHolder = surfaceView.getHolder(); + mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + if (mCamera == null) { + //打开相机 + openCamera(); + } + try { + //预览画面 + mCamera.setPreviewDisplay(mSurfaceHolder); + } catch (IOException e) { + e.printStackTrace(); + } + //开始预览 + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + releaseCamera(); //释放相机资源 + } + }); + mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置 + } + + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + camera.addCallbackBuffer(data); + Camera.Size size = camera.getParameters().getPreviewSize();//必须是相机支持的预览尺寸,否则颜色YUV空间会错位 + Bitmap originBitmap = imageHelper.nv21ToBitmap(data, size.width, size.height); + //要使用Android内置的人脸识别,需要将Bitmap对象转为RGB_565格式,否则无法识别 +// Bitmap faceDetectorBitmap = originBitmap.copy(Bitmap.Config.RGB_565, true); +// FaceDetector.Face[] faces = new FaceDetector.Face[1]; +// FaceDetector faceDetector = new FaceDetector(faceDetectorBitmap.getWidth(), faceDetectorBitmap.getHeight(), 1); +// int faceSum = faceDetector.findFaces(faceDetectorBitmap, faces); +// if (faceSum == 1) { + bitmapStack.push(originBitmap); + if (bitmapStack.size() >= 5) {//当栈里有5张bitmap之后才开始识别 + if (isCanLogin) { + isCanLogin = false; + Bitmap bitmap = bitmapStack.pop(); + Intent intent = new Intent(); + intent.putExtra("imageToBase64", ImageHelper.imageToBase64(bitmap)); + setResult(Activity.RESULT_OK, intent); + finish(); + } else { + finish(); + } + } +// } else { +// Log.d(TAG, "detectorFace: 未检测到人脸"); +// } + } + + /** + * 打开相机 + */ + private void openCamera() { + try { + mCamera = Camera.open(1); + initParameters(mCamera); //初始化相机配置信息 + mCamera.setPreviewCallback(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化相机属性 + */ + private void initParameters(Camera camera) { + try { + Camera.Parameters mParameters = camera.getParameters(); + mParameters.setPreviewFormat(ImageFormat.NV21); //设置预览图片的格式 + //获取与指定宽高相等或最接近的尺寸 + //设置预览尺寸 + Camera.Size bestPreviewSize = obtainBestSize(preViewWidth, preViewHeight, mParameters.getSupportedPreviewSizes()); + mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height); + //设置保存图片尺寸 +// Camera.Size bestPicSize = obtainBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes()); +// mParameters.setPictureSize(bestPicSize.width, bestPicSize.height); + //对焦模式 + mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + camera.setDisplayOrientation(90); + camera.setParameters(mParameters); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取最合适的尺寸 + */ + private Camera.Size obtainBestSize(int targetWidth, int targetHeight, List sizeList) { + Camera.Size bestSize = null; + int targetRatio = targetHeight / targetWidth;//目标大小的宽高比 + int minDiff = targetRatio; + + for (Camera.Size size : sizeList) { + if (size.width == targetHeight && size.height == targetWidth) { + bestSize = size; + break; + } + int supportedRatio = (size.width / size.height); + if (Math.abs(supportedRatio - targetRatio) < minDiff) { + minDiff = Math.abs(supportedRatio - targetRatio); + bestSize = size; + } + } + return bestSize; + } + + /** + * 释放相机资源 + */ + private void releaseCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java index 98aef9d..30c26c8 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java @@ -8,14 +8,15 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.Nullable; import com.casic.birmm.hxrq.R; -import com.casic.birmm.hxrq.base.DoubleClickExitActivity; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -28,23 +29,16 @@ import com.casic.birmm.hxrq.mvp.view.IFaceLoginView; import com.casic.birmm.hxrq.mvp.view.ILoginView; import com.casic.birmm.hxrq.mvp.view.IQrCodeDataView; -import com.casic.birmm.hxrq.utils.FileUtils; -import com.casic.birmm.hxrq.utils.GlideLoadEngine; +import com.casic.birmm.hxrq.utils.Constant; import com.casic.birmm.hxrq.utils.RSAUtils; import com.casic.birmm.hxrq.utils.SaveKeyValues; -import com.casic.birmm.hxrq.utils.StringHelper; import com.casic.birmm.hxrq.utils.TokenHelper; import com.google.gson.Gson; -import com.luck.picture.lib.PictureSelector; -import com.luck.picture.lib.config.PictureConfig; -import com.luck.picture.lib.config.PictureMimeType; -import com.luck.picture.lib.entity.LocalMedia; import com.qmuiteam.qmui.util.QMUIStatusBarHelper; import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUITipDialog; import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton; -import java.io.File; import java.security.PublicKey; import butterknife.BindView; @@ -53,15 +47,11 @@ import cn.bertsir.zbar.QrConfig; import cn.bertsir.zbar.QrManager; import cn.bertsir.zbar.view.ScanLineView; -import top.zibin.luban.CompressionPredicate; -import top.zibin.luban.Luban; -import top.zibin.luban.OnCompressListener; -public class LoginActivity extends DoubleClickExitActivity - implements View.OnClickListener, IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { +public class LoginActivity extends BaseActivity implements View.OnClickListener, + IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { private static final String TAG = "LoginActivity"; - @BindView(R.id.userNameView) EditText userNameView; @BindView(R.id.userPasswordView) @@ -76,8 +66,8 @@ private LoginPresenterImpl loginPresenter; private QrCodePresenterImpl qrCodePresenter; private FaceLoginPresenterImpl faceLoginPresenter; - private String userName; - private String userPassword; + private boolean isPasswordLogin = false; + private String qrCode = ""; @Override public int initLayoutView() { @@ -86,20 +76,29 @@ @Override protected void setupTopBarLayout() { - //TODO 此页面无需实现 + //设置状态栏黑色字体图标 + QMUIStatusBarHelper.setStatusBarLightMode(this); } @Override public void initData() { - //设置状态栏黑色字体图标 - QMUIStatusBarHelper.setStatusBarLightMode(this); - String userName = (String) SaveKeyValues.getValue("userName", ""); String userPassword = (String) SaveKeyValues.getValue("userPassword", ""); + userNameView.setText(userName); + userPasswordView.setText(userPassword); if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(userPassword)) { - userNameView.setText(userName); - userPasswordView.setText(userPassword); + rememberPasswordView.setChecked(true); + } else { + rememberPasswordView.setChecked(false); } + rememberPasswordView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!isChecked) { + SaveKeyValues.removeKey("userPassword"); + } + } + }); loadingDialog = new QMUITipDialog.Builder(this) .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING) .setTipWord("登陆中,请稍后") @@ -124,14 +123,9 @@ public void onClick(View v) { switch (v.getId()) { case R.id.loginButton: - userName = userNameView.getText().toString(); - userPassword = userPasswordView.getText().toString(); - if (rememberPasswordView.isChecked()) { - SaveKeyValues.putValue("userName", userName); - SaveKeyValues.putValue("userPassword", userPassword); - } //密码登录前需要验证sid authenticatePresenter.onReadyRetrofitRequest(); + isPasswordLogin = true; break; case R.id.changeLoginModeView: //首次登录不可用扫码,因为还未注册 @@ -169,50 +163,19 @@ } private void captureFaceData() { - //TODO 调相机,捕获人脸数据,并保存为文件得到路径 - PictureSelector.create(this) - .openCamera(PictureMimeType.ofImage()) - .imageEngine(GlideLoadEngine.createGlideEngine()) - .maxSelectNum(1) - .forResult(PictureConfig.REQUEST_CAMERA); + // 调相机,捕获人脸数据,并保存为文件得到路径 + startActivityForResult(new Intent(this, FacePreViewActivity.class), Constant.FACE_DETECTOR_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - if (requestCode == PictureConfig.REQUEST_CAMERA) { - LocalMedia localMedia = PictureSelector.obtainMultipleResult(data).get(0); - Luban.with(this) - .load(localMedia.getRealPath()) - .ignoreBy(100) - .setTargetDir(FileUtils.getFileDir("CompressImageFile")) - .filter(new CompressionPredicate() { - @Override - public boolean apply(String path) { - return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif")); - } - }) - .setCompressListener(new OnCompressListener() { - @Override - public void onStart() { - // TODO 压缩开始前调用,可以在方法内启动 loading UI - } - - @Override - public void onSuccess(File file) { - String imageToBase64 = StringHelper.imageToBase64(file); - - ImageBean imageBean = new ImageBean(); - imageBean.setImage(imageToBase64); - faceLoginPresenter.onReadyRetrofitRequest(imageBean); - } - - @Override - public void onError(Throwable e) { - // TODO 当压缩过程出现问题时调用 - } - }).launch(); + if (requestCode == Constant.FACE_DETECTOR_CODE) { + String imageToBase64 = data.getStringExtra("imageToBase64"); + ImageBean imageBean = new ImageBean(); + imageBean.setImage(imageToBase64); + faceLoginPresenter.onReadyRetrofitRequest(imageBean); } } } @@ -232,7 +195,7 @@ .setPlaySound(true)//是否扫描成功后bi~的声音 .setDingPath(R.raw.qrcode)//设置提示音(不设置为默认的Ding~) .setIsOnlyCenter(true)//是否只识别框中内容(默认为全屏识别) - .setTitleBackgroudColor(Color.parseColor("#262020"))//设置状态栏颜色 + .setTitleBackgroudColor(R.color.black)//设置状态栏颜色 .setTitleTextColor(Color.WHITE)//设置Title文字颜色 .setScreenOrientation(QrConfig.SCREEN_PORTRAIT)//设置屏幕方式 .setScanLineStyle(ScanLineView.style_hybrid)//扫描线样式 @@ -241,8 +204,8 @@ QrManager.getInstance().init(qrConfig).startScan(this, new QrManager.OnScanResultCallback() { @Override public void onScanSuccess(final ScanResult result) { -// Log.d(TAG, "扫码结果: " + result.content); - qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), result.content); + qrCode = result.content; + authenticatePresenter.onReadyRetrofitRequest();//需要时时保持最新token,所以扫码登录之前需要获取最新token } }); } @@ -254,9 +217,15 @@ @Override public void authenticateResult(PublicKeyBean result) { - Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); +// Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); if (result.isSuccess()) { PublicKey publicKey = RSAUtils.keyStrToPublicKey(result.getData().getPublicKey()); + String userName = userNameView.getText().toString(); + String userPassword = userPasswordView.getText().toString(); + if (rememberPasswordView.isChecked()) { + SaveKeyValues.putValue("userName", userName); + SaveKeyValues.putValue("userPassword", userPassword); + } if (TextUtils.isEmpty(userName)) { Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show(); return; @@ -266,7 +235,6 @@ return; } String dataByPublicKey = RSAUtils.encryptDataByPublicKey(userPassword.getBytes(), publicKey); - Log.d(TAG, "authenticateResult: 验证成功,开始登录"); //登录并获取Token,POST请求 loginPresenter.onReadyRetrofitRequest(result.getData().getSid(), userName, dataByPublicKey); } else { @@ -283,11 +251,14 @@ String token = result.getData().getToken(); if (!TextUtils.isEmpty(token)) { //获取用户信息 - Log.d(TAG, "obtainLoginResult: 获取Token成功"); TokenHelper.saveToken(token); //验证成功登录 - startActivity(new Intent(this, MainActivity.class)); - finish(); + if (isPasswordLogin) { + startActivity(new Intent(this, MainActivity.class)); + finish(); + } else { + qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), qrCode); + } } } @@ -307,15 +278,17 @@ } @Override - public void obtainFaceLoginData(FaceLoginResultBean resultBean) { -// Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); - if (resultBean.getCode() == 200) { + public void obtainFaceLoginData(FaceResultBean resultBean) { + Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); + if (resultBean.isSuccess()) { + //{"code":200,"data":{"kaptcha":"","token":"9135bcb7-4f39-4b7a-a10e-555406ddb9e1"},"exceptionClazz":"","message":"登录成功","success":true} TokenHelper.saveToken(resultBean.getData().getToken()); //验证成功登录 startActivity(new Intent(this, MainActivity.class)); finish(); } else { - Toast.makeText(this, "无法解析人脸", Toast.LENGTH_SHORT).show(); + //{"code":200,"data":"","exceptionClazz":"","message":"图片中没有人脸","success":false} + Toast.makeText(this, "人脸识别失败", Toast.LENGTH_SHORT).show(); } } @@ -336,5 +309,8 @@ if (qrCodePresenter != null) { qrCodePresenter.disposeRetrofitRequest(); } + if (faceLoginPresenter != null) { + faceLoginPresenter.disposeRetrofitRequest(); + } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java index e8e9b75..759a94d 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java @@ -9,4 +9,5 @@ Manifest.permission.WRITE_EXTERNAL_STORAGE}; public static final int PERMISSIONS_CODE = 999; + public static final int FACE_DETECTOR_CODE = 998; } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java new file mode 100644 index 0000000..b774ee9 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java @@ -0,0 +1,95 @@ +package com.casic.birmm.hxrq.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.ImageFormat; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.YuvImage; +import android.util.Base64; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class ImageHelper { + + public ImageHelper(Context context) { + + } + + public Bitmap nv21ToBitmap(byte[] nv21, int width, int height) { + Bitmap bitmap = null; + try { + final YuvImage image = new YuvImage(nv21, ImageFormat.NV21, width, height, null); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + image.compressToJpeg(new Rect(0, 0, width, height), 80, outputStream); + final Bitmap bmp = BitmapFactory.decodeByteArray(outputStream.toByteArray(), 0, outputStream.size()); + bitmap = rotateImageView(-90, bmp); + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return bitmap; + } + + public Bitmap rotateImageView(int angle, Bitmap bitmap) { + //旋转图片 动作 + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + // 创建新的图片 + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(File file) { + if (file == null) { + return null; + } + try { + FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int n; + while ((n = fis.read(b)) != -1) { + bos.write(b, 0, n); + } + fis.close(); + bos.close(); + + byte[] imgBytes = bos.toByteArray(); + String result = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (Exception e) { + return null; + } + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);//压缩质量 + + outputStream.flush(); + outputStream.close(); + + byte[] bitmapBytes = outputStream.toByteArray(); + String result = Base64.encodeToString(bitmapBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (IOException e) { + return null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java index f4af6a5..e7772dd 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java @@ -3,33 +3,26 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; -import android.util.Log; public class SaveKeyValues { - private static final String TAG = "SaveKeyValues"; - - @SuppressLint({"StaticFieldLeak"}) - private static Context context; private static SharedPreferences sharedPreferences; private static SharedPreferences.Editor editor; - private static String fileName; + @SuppressLint("CommitPrefEdits") public static void initSharedPreferences(Context mContext) { - context = mContext.getApplicationContext(); - String packageName = context.getPackageName(); + String packageName = mContext.getPackageName(); //获取到的包名带有“.”方便命名,取最后一个作为sp文件名,例如:com.casic.dcms String[] split = packageName.split("\\.");//先转义.之后才能分割 int length = split.length; - fileName = split[length - 1]; - Log.d(TAG, fileName); + String fileName = split[length - 1]; + sharedPreferences = mContext.getSharedPreferences(fileName, Context.MODE_PRIVATE); + editor = sharedPreferences.edit(); } /** * 存储 */ public static void putValue(String key, Object object) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); - editor = sharedPreferences.edit(); if (object instanceof String) { editor.putString(key, (String) object); } else if (object instanceof Integer) { @@ -50,7 +43,6 @@ * 获取保存的数据 */ public static Object getValue(String key, Object defaultObject) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); if (defaultObject instanceof String) { return sharedPreferences.getString(key, (String) defaultObject); } else if (defaultObject instanceof Integer) { @@ -86,7 +78,6 @@ * 查询某个key是否存在 */ public static boolean containsKey(String key) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); return sharedPreferences.contains(key); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java deleted file mode 100644 index 0ebf16a..0000000 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.casic.birmm.hxrq.utils; - -import android.util.Base64; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; - -/** - * @Author: Pengxh - * @Time: 2021/4/9 15:12 - * @Email: 290677893@qq.com - **/ -public class StringHelper { - /** - * 获取图片base64编码 - */ - public static String imageToBase64(File file) { - if (file == null) { - return null; - } - try { - FileInputStream fis = new FileInputStream(file); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] b = new byte[1024]; - int n; - while ((n = fis.read(b)) != -1) { - bos.write(b, 0, n); - } - fis.close(); - bos.close(); - - byte[] imgBytes = bos.toByteArray(); - String s = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); - return s.replace("-", "+") - .replace("_", "/"); - } catch (Exception e) { - return null; - } - } -} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java index 8fe5264..1de1ff4 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.utils.retrofit; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -49,6 +49,6 @@ */ @Headers({"Content-Type: application/json"}) @POST("/cockpit/face/login") - Observable getFaceLoginResult( + Observable getFaceLoginResult( @Body ImageBean imageBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java index ef4307e..d481055 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java @@ -2,7 +2,7 @@ import android.util.Log; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -10,7 +10,6 @@ import com.casic.birmm.hxrq.utils.HttpConfig; import org.jetbrains.annotations.NotNull; -import org.json.JSONObject; import java.util.concurrent.TimeUnit; @@ -79,7 +78,7 @@ /** * 人脸识别登录结果 */ - public static Observable getFaceResult(String baseUrl, ImageBean imageBean) { + public static Observable getFaceResult(String baseUrl, ImageBean imageBean) { Retrofit retrofit = createRetrofit(baseUrl); RetrofitService service = retrofit.create(RetrofitService.class); return service.getFaceLoginResult(imageBean); diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java new file mode 100644 index 0000000..4109e3c --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java @@ -0,0 +1,184 @@ +package com.casic.birmm.hxrq.ui; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.NonNull; + +import com.casic.birmm.hxrq.R; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.utils.ImageHelper; + +import java.io.IOException; +import java.util.List; +import java.util.Stack; + +import butterknife.BindView; + +public class FacePreViewActivity extends BaseActivity implements Camera.PreviewCallback { + + private static final int preViewWidth = 720; + private static final int preViewHeight = 1280; + @BindView(R.id.surfaceView) + SurfaceView surfaceView; + private SurfaceHolder mSurfaceHolder; + private Camera mCamera; + private ImageHelper imageHelper; + private Stack bitmapStack; + private boolean isCanLogin = true; + + @Override + public int initLayoutView() { + return R.layout.activity_face; + } + + @Override + protected void setupTopBarLayout() { + + } + + @Override + public void initData() { + imageHelper = new ImageHelper(this); + bitmapStack = new Stack<>(); + } + + @Override + public void initEvent() { + // 绑定SurfaceView,取得SurfaceHolder对象 + mSurfaceHolder = surfaceView.getHolder(); + mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + if (mCamera == null) { + //打开相机 + openCamera(); + } + try { + //预览画面 + mCamera.setPreviewDisplay(mSurfaceHolder); + } catch (IOException e) { + e.printStackTrace(); + } + //开始预览 + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + releaseCamera(); //释放相机资源 + } + }); + mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置 + } + + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + camera.addCallbackBuffer(data); + Camera.Size size = camera.getParameters().getPreviewSize();//必须是相机支持的预览尺寸,否则颜色YUV空间会错位 + Bitmap originBitmap = imageHelper.nv21ToBitmap(data, size.width, size.height); + //要使用Android内置的人脸识别,需要将Bitmap对象转为RGB_565格式,否则无法识别 +// Bitmap faceDetectorBitmap = originBitmap.copy(Bitmap.Config.RGB_565, true); +// FaceDetector.Face[] faces = new FaceDetector.Face[1]; +// FaceDetector faceDetector = new FaceDetector(faceDetectorBitmap.getWidth(), faceDetectorBitmap.getHeight(), 1); +// int faceSum = faceDetector.findFaces(faceDetectorBitmap, faces); +// if (faceSum == 1) { + bitmapStack.push(originBitmap); + if (bitmapStack.size() >= 5) {//当栈里有5张bitmap之后才开始识别 + if (isCanLogin) { + isCanLogin = false; + Bitmap bitmap = bitmapStack.pop(); + Intent intent = new Intent(); + intent.putExtra("imageToBase64", ImageHelper.imageToBase64(bitmap)); + setResult(Activity.RESULT_OK, intent); + finish(); + } else { + finish(); + } + } +// } else { +// Log.d(TAG, "detectorFace: 未检测到人脸"); +// } + } + + /** + * 打开相机 + */ + private void openCamera() { + try { + mCamera = Camera.open(1); + initParameters(mCamera); //初始化相机配置信息 + mCamera.setPreviewCallback(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化相机属性 + */ + private void initParameters(Camera camera) { + try { + Camera.Parameters mParameters = camera.getParameters(); + mParameters.setPreviewFormat(ImageFormat.NV21); //设置预览图片的格式 + //获取与指定宽高相等或最接近的尺寸 + //设置预览尺寸 + Camera.Size bestPreviewSize = obtainBestSize(preViewWidth, preViewHeight, mParameters.getSupportedPreviewSizes()); + mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height); + //设置保存图片尺寸 +// Camera.Size bestPicSize = obtainBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes()); +// mParameters.setPictureSize(bestPicSize.width, bestPicSize.height); + //对焦模式 + mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + camera.setDisplayOrientation(90); + camera.setParameters(mParameters); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取最合适的尺寸 + */ + private Camera.Size obtainBestSize(int targetWidth, int targetHeight, List sizeList) { + Camera.Size bestSize = null; + int targetRatio = targetHeight / targetWidth;//目标大小的宽高比 + int minDiff = targetRatio; + + for (Camera.Size size : sizeList) { + if (size.width == targetHeight && size.height == targetWidth) { + bestSize = size; + break; + } + int supportedRatio = (size.width / size.height); + if (Math.abs(supportedRatio - targetRatio) < minDiff) { + minDiff = Math.abs(supportedRatio - targetRatio); + bestSize = size; + } + } + return bestSize; + } + + /** + * 释放相机资源 + */ + private void releaseCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java index 98aef9d..30c26c8 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java @@ -8,14 +8,15 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.Nullable; import com.casic.birmm.hxrq.R; -import com.casic.birmm.hxrq.base.DoubleClickExitActivity; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -28,23 +29,16 @@ import com.casic.birmm.hxrq.mvp.view.IFaceLoginView; import com.casic.birmm.hxrq.mvp.view.ILoginView; import com.casic.birmm.hxrq.mvp.view.IQrCodeDataView; -import com.casic.birmm.hxrq.utils.FileUtils; -import com.casic.birmm.hxrq.utils.GlideLoadEngine; +import com.casic.birmm.hxrq.utils.Constant; import com.casic.birmm.hxrq.utils.RSAUtils; import com.casic.birmm.hxrq.utils.SaveKeyValues; -import com.casic.birmm.hxrq.utils.StringHelper; import com.casic.birmm.hxrq.utils.TokenHelper; import com.google.gson.Gson; -import com.luck.picture.lib.PictureSelector; -import com.luck.picture.lib.config.PictureConfig; -import com.luck.picture.lib.config.PictureMimeType; -import com.luck.picture.lib.entity.LocalMedia; import com.qmuiteam.qmui.util.QMUIStatusBarHelper; import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUITipDialog; import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton; -import java.io.File; import java.security.PublicKey; import butterknife.BindView; @@ -53,15 +47,11 @@ import cn.bertsir.zbar.QrConfig; import cn.bertsir.zbar.QrManager; import cn.bertsir.zbar.view.ScanLineView; -import top.zibin.luban.CompressionPredicate; -import top.zibin.luban.Luban; -import top.zibin.luban.OnCompressListener; -public class LoginActivity extends DoubleClickExitActivity - implements View.OnClickListener, IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { +public class LoginActivity extends BaseActivity implements View.OnClickListener, + IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { private static final String TAG = "LoginActivity"; - @BindView(R.id.userNameView) EditText userNameView; @BindView(R.id.userPasswordView) @@ -76,8 +66,8 @@ private LoginPresenterImpl loginPresenter; private QrCodePresenterImpl qrCodePresenter; private FaceLoginPresenterImpl faceLoginPresenter; - private String userName; - private String userPassword; + private boolean isPasswordLogin = false; + private String qrCode = ""; @Override public int initLayoutView() { @@ -86,20 +76,29 @@ @Override protected void setupTopBarLayout() { - //TODO 此页面无需实现 + //设置状态栏黑色字体图标 + QMUIStatusBarHelper.setStatusBarLightMode(this); } @Override public void initData() { - //设置状态栏黑色字体图标 - QMUIStatusBarHelper.setStatusBarLightMode(this); - String userName = (String) SaveKeyValues.getValue("userName", ""); String userPassword = (String) SaveKeyValues.getValue("userPassword", ""); + userNameView.setText(userName); + userPasswordView.setText(userPassword); if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(userPassword)) { - userNameView.setText(userName); - userPasswordView.setText(userPassword); + rememberPasswordView.setChecked(true); + } else { + rememberPasswordView.setChecked(false); } + rememberPasswordView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!isChecked) { + SaveKeyValues.removeKey("userPassword"); + } + } + }); loadingDialog = new QMUITipDialog.Builder(this) .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING) .setTipWord("登陆中,请稍后") @@ -124,14 +123,9 @@ public void onClick(View v) { switch (v.getId()) { case R.id.loginButton: - userName = userNameView.getText().toString(); - userPassword = userPasswordView.getText().toString(); - if (rememberPasswordView.isChecked()) { - SaveKeyValues.putValue("userName", userName); - SaveKeyValues.putValue("userPassword", userPassword); - } //密码登录前需要验证sid authenticatePresenter.onReadyRetrofitRequest(); + isPasswordLogin = true; break; case R.id.changeLoginModeView: //首次登录不可用扫码,因为还未注册 @@ -169,50 +163,19 @@ } private void captureFaceData() { - //TODO 调相机,捕获人脸数据,并保存为文件得到路径 - PictureSelector.create(this) - .openCamera(PictureMimeType.ofImage()) - .imageEngine(GlideLoadEngine.createGlideEngine()) - .maxSelectNum(1) - .forResult(PictureConfig.REQUEST_CAMERA); + // 调相机,捕获人脸数据,并保存为文件得到路径 + startActivityForResult(new Intent(this, FacePreViewActivity.class), Constant.FACE_DETECTOR_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - if (requestCode == PictureConfig.REQUEST_CAMERA) { - LocalMedia localMedia = PictureSelector.obtainMultipleResult(data).get(0); - Luban.with(this) - .load(localMedia.getRealPath()) - .ignoreBy(100) - .setTargetDir(FileUtils.getFileDir("CompressImageFile")) - .filter(new CompressionPredicate() { - @Override - public boolean apply(String path) { - return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif")); - } - }) - .setCompressListener(new OnCompressListener() { - @Override - public void onStart() { - // TODO 压缩开始前调用,可以在方法内启动 loading UI - } - - @Override - public void onSuccess(File file) { - String imageToBase64 = StringHelper.imageToBase64(file); - - ImageBean imageBean = new ImageBean(); - imageBean.setImage(imageToBase64); - faceLoginPresenter.onReadyRetrofitRequest(imageBean); - } - - @Override - public void onError(Throwable e) { - // TODO 当压缩过程出现问题时调用 - } - }).launch(); + if (requestCode == Constant.FACE_DETECTOR_CODE) { + String imageToBase64 = data.getStringExtra("imageToBase64"); + ImageBean imageBean = new ImageBean(); + imageBean.setImage(imageToBase64); + faceLoginPresenter.onReadyRetrofitRequest(imageBean); } } } @@ -232,7 +195,7 @@ .setPlaySound(true)//是否扫描成功后bi~的声音 .setDingPath(R.raw.qrcode)//设置提示音(不设置为默认的Ding~) .setIsOnlyCenter(true)//是否只识别框中内容(默认为全屏识别) - .setTitleBackgroudColor(Color.parseColor("#262020"))//设置状态栏颜色 + .setTitleBackgroudColor(R.color.black)//设置状态栏颜色 .setTitleTextColor(Color.WHITE)//设置Title文字颜色 .setScreenOrientation(QrConfig.SCREEN_PORTRAIT)//设置屏幕方式 .setScanLineStyle(ScanLineView.style_hybrid)//扫描线样式 @@ -241,8 +204,8 @@ QrManager.getInstance().init(qrConfig).startScan(this, new QrManager.OnScanResultCallback() { @Override public void onScanSuccess(final ScanResult result) { -// Log.d(TAG, "扫码结果: " + result.content); - qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), result.content); + qrCode = result.content; + authenticatePresenter.onReadyRetrofitRequest();//需要时时保持最新token,所以扫码登录之前需要获取最新token } }); } @@ -254,9 +217,15 @@ @Override public void authenticateResult(PublicKeyBean result) { - Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); +// Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); if (result.isSuccess()) { PublicKey publicKey = RSAUtils.keyStrToPublicKey(result.getData().getPublicKey()); + String userName = userNameView.getText().toString(); + String userPassword = userPasswordView.getText().toString(); + if (rememberPasswordView.isChecked()) { + SaveKeyValues.putValue("userName", userName); + SaveKeyValues.putValue("userPassword", userPassword); + } if (TextUtils.isEmpty(userName)) { Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show(); return; @@ -266,7 +235,6 @@ return; } String dataByPublicKey = RSAUtils.encryptDataByPublicKey(userPassword.getBytes(), publicKey); - Log.d(TAG, "authenticateResult: 验证成功,开始登录"); //登录并获取Token,POST请求 loginPresenter.onReadyRetrofitRequest(result.getData().getSid(), userName, dataByPublicKey); } else { @@ -283,11 +251,14 @@ String token = result.getData().getToken(); if (!TextUtils.isEmpty(token)) { //获取用户信息 - Log.d(TAG, "obtainLoginResult: 获取Token成功"); TokenHelper.saveToken(token); //验证成功登录 - startActivity(new Intent(this, MainActivity.class)); - finish(); + if (isPasswordLogin) { + startActivity(new Intent(this, MainActivity.class)); + finish(); + } else { + qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), qrCode); + } } } @@ -307,15 +278,17 @@ } @Override - public void obtainFaceLoginData(FaceLoginResultBean resultBean) { -// Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); - if (resultBean.getCode() == 200) { + public void obtainFaceLoginData(FaceResultBean resultBean) { + Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); + if (resultBean.isSuccess()) { + //{"code":200,"data":{"kaptcha":"","token":"9135bcb7-4f39-4b7a-a10e-555406ddb9e1"},"exceptionClazz":"","message":"登录成功","success":true} TokenHelper.saveToken(resultBean.getData().getToken()); //验证成功登录 startActivity(new Intent(this, MainActivity.class)); finish(); } else { - Toast.makeText(this, "无法解析人脸", Toast.LENGTH_SHORT).show(); + //{"code":200,"data":"","exceptionClazz":"","message":"图片中没有人脸","success":false} + Toast.makeText(this, "人脸识别失败", Toast.LENGTH_SHORT).show(); } } @@ -336,5 +309,8 @@ if (qrCodePresenter != null) { qrCodePresenter.disposeRetrofitRequest(); } + if (faceLoginPresenter != null) { + faceLoginPresenter.disposeRetrofitRequest(); + } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java index e8e9b75..759a94d 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java @@ -9,4 +9,5 @@ Manifest.permission.WRITE_EXTERNAL_STORAGE}; public static final int PERMISSIONS_CODE = 999; + public static final int FACE_DETECTOR_CODE = 998; } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java new file mode 100644 index 0000000..b774ee9 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java @@ -0,0 +1,95 @@ +package com.casic.birmm.hxrq.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.ImageFormat; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.YuvImage; +import android.util.Base64; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class ImageHelper { + + public ImageHelper(Context context) { + + } + + public Bitmap nv21ToBitmap(byte[] nv21, int width, int height) { + Bitmap bitmap = null; + try { + final YuvImage image = new YuvImage(nv21, ImageFormat.NV21, width, height, null); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + image.compressToJpeg(new Rect(0, 0, width, height), 80, outputStream); + final Bitmap bmp = BitmapFactory.decodeByteArray(outputStream.toByteArray(), 0, outputStream.size()); + bitmap = rotateImageView(-90, bmp); + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return bitmap; + } + + public Bitmap rotateImageView(int angle, Bitmap bitmap) { + //旋转图片 动作 + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + // 创建新的图片 + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(File file) { + if (file == null) { + return null; + } + try { + FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int n; + while ((n = fis.read(b)) != -1) { + bos.write(b, 0, n); + } + fis.close(); + bos.close(); + + byte[] imgBytes = bos.toByteArray(); + String result = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (Exception e) { + return null; + } + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);//压缩质量 + + outputStream.flush(); + outputStream.close(); + + byte[] bitmapBytes = outputStream.toByteArray(); + String result = Base64.encodeToString(bitmapBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (IOException e) { + return null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java index f4af6a5..e7772dd 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java @@ -3,33 +3,26 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; -import android.util.Log; public class SaveKeyValues { - private static final String TAG = "SaveKeyValues"; - - @SuppressLint({"StaticFieldLeak"}) - private static Context context; private static SharedPreferences sharedPreferences; private static SharedPreferences.Editor editor; - private static String fileName; + @SuppressLint("CommitPrefEdits") public static void initSharedPreferences(Context mContext) { - context = mContext.getApplicationContext(); - String packageName = context.getPackageName(); + String packageName = mContext.getPackageName(); //获取到的包名带有“.”方便命名,取最后一个作为sp文件名,例如:com.casic.dcms String[] split = packageName.split("\\.");//先转义.之后才能分割 int length = split.length; - fileName = split[length - 1]; - Log.d(TAG, fileName); + String fileName = split[length - 1]; + sharedPreferences = mContext.getSharedPreferences(fileName, Context.MODE_PRIVATE); + editor = sharedPreferences.edit(); } /** * 存储 */ public static void putValue(String key, Object object) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); - editor = sharedPreferences.edit(); if (object instanceof String) { editor.putString(key, (String) object); } else if (object instanceof Integer) { @@ -50,7 +43,6 @@ * 获取保存的数据 */ public static Object getValue(String key, Object defaultObject) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); if (defaultObject instanceof String) { return sharedPreferences.getString(key, (String) defaultObject); } else if (defaultObject instanceof Integer) { @@ -86,7 +78,6 @@ * 查询某个key是否存在 */ public static boolean containsKey(String key) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); return sharedPreferences.contains(key); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java deleted file mode 100644 index 0ebf16a..0000000 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.casic.birmm.hxrq.utils; - -import android.util.Base64; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; - -/** - * @Author: Pengxh - * @Time: 2021/4/9 15:12 - * @Email: 290677893@qq.com - **/ -public class StringHelper { - /** - * 获取图片base64编码 - */ - public static String imageToBase64(File file) { - if (file == null) { - return null; - } - try { - FileInputStream fis = new FileInputStream(file); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] b = new byte[1024]; - int n; - while ((n = fis.read(b)) != -1) { - bos.write(b, 0, n); - } - fis.close(); - bos.close(); - - byte[] imgBytes = bos.toByteArray(); - String s = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); - return s.replace("-", "+") - .replace("_", "/"); - } catch (Exception e) { - return null; - } - } -} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java index 8fe5264..1de1ff4 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.utils.retrofit; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -49,6 +49,6 @@ */ @Headers({"Content-Type: application/json"}) @POST("/cockpit/face/login") - Observable getFaceLoginResult( + Observable getFaceLoginResult( @Body ImageBean imageBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java index ef4307e..d481055 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java @@ -2,7 +2,7 @@ import android.util.Log; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -10,7 +10,6 @@ import com.casic.birmm.hxrq.utils.HttpConfig; import org.jetbrains.annotations.NotNull; -import org.json.JSONObject; import java.util.concurrent.TimeUnit; @@ -79,7 +78,7 @@ /** * 人脸识别登录结果 */ - public static Observable getFaceResult(String baseUrl, ImageBean imageBean) { + public static Observable getFaceResult(String baseUrl, ImageBean imageBean) { Retrofit retrofit = createRetrofit(baseUrl); RetrofitService service = retrofit.create(RetrofitService.class); return service.getFaceLoginResult(imageBean); diff --git a/app/src/main/res/drawable/bg_circle_image.xml b/app/src/main/res/drawable/bg_circle_image.xml new file mode 100644 index 0000000..5b27ca4 --- /dev/null +++ b/app/src/main/res/drawable/bg_circle_image.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java new file mode 100644 index 0000000..4109e3c --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java @@ -0,0 +1,184 @@ +package com.casic.birmm.hxrq.ui; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.NonNull; + +import com.casic.birmm.hxrq.R; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.utils.ImageHelper; + +import java.io.IOException; +import java.util.List; +import java.util.Stack; + +import butterknife.BindView; + +public class FacePreViewActivity extends BaseActivity implements Camera.PreviewCallback { + + private static final int preViewWidth = 720; + private static final int preViewHeight = 1280; + @BindView(R.id.surfaceView) + SurfaceView surfaceView; + private SurfaceHolder mSurfaceHolder; + private Camera mCamera; + private ImageHelper imageHelper; + private Stack bitmapStack; + private boolean isCanLogin = true; + + @Override + public int initLayoutView() { + return R.layout.activity_face; + } + + @Override + protected void setupTopBarLayout() { + + } + + @Override + public void initData() { + imageHelper = new ImageHelper(this); + bitmapStack = new Stack<>(); + } + + @Override + public void initEvent() { + // 绑定SurfaceView,取得SurfaceHolder对象 + mSurfaceHolder = surfaceView.getHolder(); + mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + if (mCamera == null) { + //打开相机 + openCamera(); + } + try { + //预览画面 + mCamera.setPreviewDisplay(mSurfaceHolder); + } catch (IOException e) { + e.printStackTrace(); + } + //开始预览 + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + releaseCamera(); //释放相机资源 + } + }); + mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置 + } + + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + camera.addCallbackBuffer(data); + Camera.Size size = camera.getParameters().getPreviewSize();//必须是相机支持的预览尺寸,否则颜色YUV空间会错位 + Bitmap originBitmap = imageHelper.nv21ToBitmap(data, size.width, size.height); + //要使用Android内置的人脸识别,需要将Bitmap对象转为RGB_565格式,否则无法识别 +// Bitmap faceDetectorBitmap = originBitmap.copy(Bitmap.Config.RGB_565, true); +// FaceDetector.Face[] faces = new FaceDetector.Face[1]; +// FaceDetector faceDetector = new FaceDetector(faceDetectorBitmap.getWidth(), faceDetectorBitmap.getHeight(), 1); +// int faceSum = faceDetector.findFaces(faceDetectorBitmap, faces); +// if (faceSum == 1) { + bitmapStack.push(originBitmap); + if (bitmapStack.size() >= 5) {//当栈里有5张bitmap之后才开始识别 + if (isCanLogin) { + isCanLogin = false; + Bitmap bitmap = bitmapStack.pop(); + Intent intent = new Intent(); + intent.putExtra("imageToBase64", ImageHelper.imageToBase64(bitmap)); + setResult(Activity.RESULT_OK, intent); + finish(); + } else { + finish(); + } + } +// } else { +// Log.d(TAG, "detectorFace: 未检测到人脸"); +// } + } + + /** + * 打开相机 + */ + private void openCamera() { + try { + mCamera = Camera.open(1); + initParameters(mCamera); //初始化相机配置信息 + mCamera.setPreviewCallback(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化相机属性 + */ + private void initParameters(Camera camera) { + try { + Camera.Parameters mParameters = camera.getParameters(); + mParameters.setPreviewFormat(ImageFormat.NV21); //设置预览图片的格式 + //获取与指定宽高相等或最接近的尺寸 + //设置预览尺寸 + Camera.Size bestPreviewSize = obtainBestSize(preViewWidth, preViewHeight, mParameters.getSupportedPreviewSizes()); + mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height); + //设置保存图片尺寸 +// Camera.Size bestPicSize = obtainBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes()); +// mParameters.setPictureSize(bestPicSize.width, bestPicSize.height); + //对焦模式 + mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + camera.setDisplayOrientation(90); + camera.setParameters(mParameters); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取最合适的尺寸 + */ + private Camera.Size obtainBestSize(int targetWidth, int targetHeight, List sizeList) { + Camera.Size bestSize = null; + int targetRatio = targetHeight / targetWidth;//目标大小的宽高比 + int minDiff = targetRatio; + + for (Camera.Size size : sizeList) { + if (size.width == targetHeight && size.height == targetWidth) { + bestSize = size; + break; + } + int supportedRatio = (size.width / size.height); + if (Math.abs(supportedRatio - targetRatio) < minDiff) { + minDiff = Math.abs(supportedRatio - targetRatio); + bestSize = size; + } + } + return bestSize; + } + + /** + * 释放相机资源 + */ + private void releaseCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java index 98aef9d..30c26c8 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java @@ -8,14 +8,15 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.Nullable; import com.casic.birmm.hxrq.R; -import com.casic.birmm.hxrq.base.DoubleClickExitActivity; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -28,23 +29,16 @@ import com.casic.birmm.hxrq.mvp.view.IFaceLoginView; import com.casic.birmm.hxrq.mvp.view.ILoginView; import com.casic.birmm.hxrq.mvp.view.IQrCodeDataView; -import com.casic.birmm.hxrq.utils.FileUtils; -import com.casic.birmm.hxrq.utils.GlideLoadEngine; +import com.casic.birmm.hxrq.utils.Constant; import com.casic.birmm.hxrq.utils.RSAUtils; import com.casic.birmm.hxrq.utils.SaveKeyValues; -import com.casic.birmm.hxrq.utils.StringHelper; import com.casic.birmm.hxrq.utils.TokenHelper; import com.google.gson.Gson; -import com.luck.picture.lib.PictureSelector; -import com.luck.picture.lib.config.PictureConfig; -import com.luck.picture.lib.config.PictureMimeType; -import com.luck.picture.lib.entity.LocalMedia; import com.qmuiteam.qmui.util.QMUIStatusBarHelper; import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUITipDialog; import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton; -import java.io.File; import java.security.PublicKey; import butterknife.BindView; @@ -53,15 +47,11 @@ import cn.bertsir.zbar.QrConfig; import cn.bertsir.zbar.QrManager; import cn.bertsir.zbar.view.ScanLineView; -import top.zibin.luban.CompressionPredicate; -import top.zibin.luban.Luban; -import top.zibin.luban.OnCompressListener; -public class LoginActivity extends DoubleClickExitActivity - implements View.OnClickListener, IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { +public class LoginActivity extends BaseActivity implements View.OnClickListener, + IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { private static final String TAG = "LoginActivity"; - @BindView(R.id.userNameView) EditText userNameView; @BindView(R.id.userPasswordView) @@ -76,8 +66,8 @@ private LoginPresenterImpl loginPresenter; private QrCodePresenterImpl qrCodePresenter; private FaceLoginPresenterImpl faceLoginPresenter; - private String userName; - private String userPassword; + private boolean isPasswordLogin = false; + private String qrCode = ""; @Override public int initLayoutView() { @@ -86,20 +76,29 @@ @Override protected void setupTopBarLayout() { - //TODO 此页面无需实现 + //设置状态栏黑色字体图标 + QMUIStatusBarHelper.setStatusBarLightMode(this); } @Override public void initData() { - //设置状态栏黑色字体图标 - QMUIStatusBarHelper.setStatusBarLightMode(this); - String userName = (String) SaveKeyValues.getValue("userName", ""); String userPassword = (String) SaveKeyValues.getValue("userPassword", ""); + userNameView.setText(userName); + userPasswordView.setText(userPassword); if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(userPassword)) { - userNameView.setText(userName); - userPasswordView.setText(userPassword); + rememberPasswordView.setChecked(true); + } else { + rememberPasswordView.setChecked(false); } + rememberPasswordView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!isChecked) { + SaveKeyValues.removeKey("userPassword"); + } + } + }); loadingDialog = new QMUITipDialog.Builder(this) .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING) .setTipWord("登陆中,请稍后") @@ -124,14 +123,9 @@ public void onClick(View v) { switch (v.getId()) { case R.id.loginButton: - userName = userNameView.getText().toString(); - userPassword = userPasswordView.getText().toString(); - if (rememberPasswordView.isChecked()) { - SaveKeyValues.putValue("userName", userName); - SaveKeyValues.putValue("userPassword", userPassword); - } //密码登录前需要验证sid authenticatePresenter.onReadyRetrofitRequest(); + isPasswordLogin = true; break; case R.id.changeLoginModeView: //首次登录不可用扫码,因为还未注册 @@ -169,50 +163,19 @@ } private void captureFaceData() { - //TODO 调相机,捕获人脸数据,并保存为文件得到路径 - PictureSelector.create(this) - .openCamera(PictureMimeType.ofImage()) - .imageEngine(GlideLoadEngine.createGlideEngine()) - .maxSelectNum(1) - .forResult(PictureConfig.REQUEST_CAMERA); + // 调相机,捕获人脸数据,并保存为文件得到路径 + startActivityForResult(new Intent(this, FacePreViewActivity.class), Constant.FACE_DETECTOR_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - if (requestCode == PictureConfig.REQUEST_CAMERA) { - LocalMedia localMedia = PictureSelector.obtainMultipleResult(data).get(0); - Luban.with(this) - .load(localMedia.getRealPath()) - .ignoreBy(100) - .setTargetDir(FileUtils.getFileDir("CompressImageFile")) - .filter(new CompressionPredicate() { - @Override - public boolean apply(String path) { - return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif")); - } - }) - .setCompressListener(new OnCompressListener() { - @Override - public void onStart() { - // TODO 压缩开始前调用,可以在方法内启动 loading UI - } - - @Override - public void onSuccess(File file) { - String imageToBase64 = StringHelper.imageToBase64(file); - - ImageBean imageBean = new ImageBean(); - imageBean.setImage(imageToBase64); - faceLoginPresenter.onReadyRetrofitRequest(imageBean); - } - - @Override - public void onError(Throwable e) { - // TODO 当压缩过程出现问题时调用 - } - }).launch(); + if (requestCode == Constant.FACE_DETECTOR_CODE) { + String imageToBase64 = data.getStringExtra("imageToBase64"); + ImageBean imageBean = new ImageBean(); + imageBean.setImage(imageToBase64); + faceLoginPresenter.onReadyRetrofitRequest(imageBean); } } } @@ -232,7 +195,7 @@ .setPlaySound(true)//是否扫描成功后bi~的声音 .setDingPath(R.raw.qrcode)//设置提示音(不设置为默认的Ding~) .setIsOnlyCenter(true)//是否只识别框中内容(默认为全屏识别) - .setTitleBackgroudColor(Color.parseColor("#262020"))//设置状态栏颜色 + .setTitleBackgroudColor(R.color.black)//设置状态栏颜色 .setTitleTextColor(Color.WHITE)//设置Title文字颜色 .setScreenOrientation(QrConfig.SCREEN_PORTRAIT)//设置屏幕方式 .setScanLineStyle(ScanLineView.style_hybrid)//扫描线样式 @@ -241,8 +204,8 @@ QrManager.getInstance().init(qrConfig).startScan(this, new QrManager.OnScanResultCallback() { @Override public void onScanSuccess(final ScanResult result) { -// Log.d(TAG, "扫码结果: " + result.content); - qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), result.content); + qrCode = result.content; + authenticatePresenter.onReadyRetrofitRequest();//需要时时保持最新token,所以扫码登录之前需要获取最新token } }); } @@ -254,9 +217,15 @@ @Override public void authenticateResult(PublicKeyBean result) { - Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); +// Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); if (result.isSuccess()) { PublicKey publicKey = RSAUtils.keyStrToPublicKey(result.getData().getPublicKey()); + String userName = userNameView.getText().toString(); + String userPassword = userPasswordView.getText().toString(); + if (rememberPasswordView.isChecked()) { + SaveKeyValues.putValue("userName", userName); + SaveKeyValues.putValue("userPassword", userPassword); + } if (TextUtils.isEmpty(userName)) { Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show(); return; @@ -266,7 +235,6 @@ return; } String dataByPublicKey = RSAUtils.encryptDataByPublicKey(userPassword.getBytes(), publicKey); - Log.d(TAG, "authenticateResult: 验证成功,开始登录"); //登录并获取Token,POST请求 loginPresenter.onReadyRetrofitRequest(result.getData().getSid(), userName, dataByPublicKey); } else { @@ -283,11 +251,14 @@ String token = result.getData().getToken(); if (!TextUtils.isEmpty(token)) { //获取用户信息 - Log.d(TAG, "obtainLoginResult: 获取Token成功"); TokenHelper.saveToken(token); //验证成功登录 - startActivity(new Intent(this, MainActivity.class)); - finish(); + if (isPasswordLogin) { + startActivity(new Intent(this, MainActivity.class)); + finish(); + } else { + qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), qrCode); + } } } @@ -307,15 +278,17 @@ } @Override - public void obtainFaceLoginData(FaceLoginResultBean resultBean) { -// Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); - if (resultBean.getCode() == 200) { + public void obtainFaceLoginData(FaceResultBean resultBean) { + Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); + if (resultBean.isSuccess()) { + //{"code":200,"data":{"kaptcha":"","token":"9135bcb7-4f39-4b7a-a10e-555406ddb9e1"},"exceptionClazz":"","message":"登录成功","success":true} TokenHelper.saveToken(resultBean.getData().getToken()); //验证成功登录 startActivity(new Intent(this, MainActivity.class)); finish(); } else { - Toast.makeText(this, "无法解析人脸", Toast.LENGTH_SHORT).show(); + //{"code":200,"data":"","exceptionClazz":"","message":"图片中没有人脸","success":false} + Toast.makeText(this, "人脸识别失败", Toast.LENGTH_SHORT).show(); } } @@ -336,5 +309,8 @@ if (qrCodePresenter != null) { qrCodePresenter.disposeRetrofitRequest(); } + if (faceLoginPresenter != null) { + faceLoginPresenter.disposeRetrofitRequest(); + } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java index e8e9b75..759a94d 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java @@ -9,4 +9,5 @@ Manifest.permission.WRITE_EXTERNAL_STORAGE}; public static final int PERMISSIONS_CODE = 999; + public static final int FACE_DETECTOR_CODE = 998; } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java new file mode 100644 index 0000000..b774ee9 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java @@ -0,0 +1,95 @@ +package com.casic.birmm.hxrq.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.ImageFormat; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.YuvImage; +import android.util.Base64; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class ImageHelper { + + public ImageHelper(Context context) { + + } + + public Bitmap nv21ToBitmap(byte[] nv21, int width, int height) { + Bitmap bitmap = null; + try { + final YuvImage image = new YuvImage(nv21, ImageFormat.NV21, width, height, null); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + image.compressToJpeg(new Rect(0, 0, width, height), 80, outputStream); + final Bitmap bmp = BitmapFactory.decodeByteArray(outputStream.toByteArray(), 0, outputStream.size()); + bitmap = rotateImageView(-90, bmp); + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return bitmap; + } + + public Bitmap rotateImageView(int angle, Bitmap bitmap) { + //旋转图片 动作 + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + // 创建新的图片 + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(File file) { + if (file == null) { + return null; + } + try { + FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int n; + while ((n = fis.read(b)) != -1) { + bos.write(b, 0, n); + } + fis.close(); + bos.close(); + + byte[] imgBytes = bos.toByteArray(); + String result = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (Exception e) { + return null; + } + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);//压缩质量 + + outputStream.flush(); + outputStream.close(); + + byte[] bitmapBytes = outputStream.toByteArray(); + String result = Base64.encodeToString(bitmapBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (IOException e) { + return null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java index f4af6a5..e7772dd 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java @@ -3,33 +3,26 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; -import android.util.Log; public class SaveKeyValues { - private static final String TAG = "SaveKeyValues"; - - @SuppressLint({"StaticFieldLeak"}) - private static Context context; private static SharedPreferences sharedPreferences; private static SharedPreferences.Editor editor; - private static String fileName; + @SuppressLint("CommitPrefEdits") public static void initSharedPreferences(Context mContext) { - context = mContext.getApplicationContext(); - String packageName = context.getPackageName(); + String packageName = mContext.getPackageName(); //获取到的包名带有“.”方便命名,取最后一个作为sp文件名,例如:com.casic.dcms String[] split = packageName.split("\\.");//先转义.之后才能分割 int length = split.length; - fileName = split[length - 1]; - Log.d(TAG, fileName); + String fileName = split[length - 1]; + sharedPreferences = mContext.getSharedPreferences(fileName, Context.MODE_PRIVATE); + editor = sharedPreferences.edit(); } /** * 存储 */ public static void putValue(String key, Object object) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); - editor = sharedPreferences.edit(); if (object instanceof String) { editor.putString(key, (String) object); } else if (object instanceof Integer) { @@ -50,7 +43,6 @@ * 获取保存的数据 */ public static Object getValue(String key, Object defaultObject) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); if (defaultObject instanceof String) { return sharedPreferences.getString(key, (String) defaultObject); } else if (defaultObject instanceof Integer) { @@ -86,7 +78,6 @@ * 查询某个key是否存在 */ public static boolean containsKey(String key) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); return sharedPreferences.contains(key); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java deleted file mode 100644 index 0ebf16a..0000000 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.casic.birmm.hxrq.utils; - -import android.util.Base64; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; - -/** - * @Author: Pengxh - * @Time: 2021/4/9 15:12 - * @Email: 290677893@qq.com - **/ -public class StringHelper { - /** - * 获取图片base64编码 - */ - public static String imageToBase64(File file) { - if (file == null) { - return null; - } - try { - FileInputStream fis = new FileInputStream(file); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] b = new byte[1024]; - int n; - while ((n = fis.read(b)) != -1) { - bos.write(b, 0, n); - } - fis.close(); - bos.close(); - - byte[] imgBytes = bos.toByteArray(); - String s = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); - return s.replace("-", "+") - .replace("_", "/"); - } catch (Exception e) { - return null; - } - } -} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java index 8fe5264..1de1ff4 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.utils.retrofit; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -49,6 +49,6 @@ */ @Headers({"Content-Type: application/json"}) @POST("/cockpit/face/login") - Observable getFaceLoginResult( + Observable getFaceLoginResult( @Body ImageBean imageBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java index ef4307e..d481055 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java @@ -2,7 +2,7 @@ import android.util.Log; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -10,7 +10,6 @@ import com.casic.birmm.hxrq.utils.HttpConfig; import org.jetbrains.annotations.NotNull; -import org.json.JSONObject; import java.util.concurrent.TimeUnit; @@ -79,7 +78,7 @@ /** * 人脸识别登录结果 */ - public static Observable getFaceResult(String baseUrl, ImageBean imageBean) { + public static Observable getFaceResult(String baseUrl, ImageBean imageBean) { Retrofit retrofit = createRetrofit(baseUrl); RetrofitService service = retrofit.create(RetrofitService.class); return service.getFaceLoginResult(imageBean); diff --git a/app/src/main/res/drawable/bg_circle_image.xml b/app/src/main/res/drawable/bg_circle_image.xml new file mode 100644 index 0000000..5b27ca4 --- /dev/null +++ b/app/src/main/res/drawable/bg_circle_image.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_face.xml b/app/src/main/res/layout/activity_face.xml new file mode 100644 index 0000000..0d2e4e0 --- /dev/null +++ b/app/src/main/res/layout/activity_face.xml @@ -0,0 +1,25 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java new file mode 100644 index 0000000..4109e3c --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java @@ -0,0 +1,184 @@ +package com.casic.birmm.hxrq.ui; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.NonNull; + +import com.casic.birmm.hxrq.R; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.utils.ImageHelper; + +import java.io.IOException; +import java.util.List; +import java.util.Stack; + +import butterknife.BindView; + +public class FacePreViewActivity extends BaseActivity implements Camera.PreviewCallback { + + private static final int preViewWidth = 720; + private static final int preViewHeight = 1280; + @BindView(R.id.surfaceView) + SurfaceView surfaceView; + private SurfaceHolder mSurfaceHolder; + private Camera mCamera; + private ImageHelper imageHelper; + private Stack bitmapStack; + private boolean isCanLogin = true; + + @Override + public int initLayoutView() { + return R.layout.activity_face; + } + + @Override + protected void setupTopBarLayout() { + + } + + @Override + public void initData() { + imageHelper = new ImageHelper(this); + bitmapStack = new Stack<>(); + } + + @Override + public void initEvent() { + // 绑定SurfaceView,取得SurfaceHolder对象 + mSurfaceHolder = surfaceView.getHolder(); + mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + if (mCamera == null) { + //打开相机 + openCamera(); + } + try { + //预览画面 + mCamera.setPreviewDisplay(mSurfaceHolder); + } catch (IOException e) { + e.printStackTrace(); + } + //开始预览 + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + releaseCamera(); //释放相机资源 + } + }); + mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置 + } + + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + camera.addCallbackBuffer(data); + Camera.Size size = camera.getParameters().getPreviewSize();//必须是相机支持的预览尺寸,否则颜色YUV空间会错位 + Bitmap originBitmap = imageHelper.nv21ToBitmap(data, size.width, size.height); + //要使用Android内置的人脸识别,需要将Bitmap对象转为RGB_565格式,否则无法识别 +// Bitmap faceDetectorBitmap = originBitmap.copy(Bitmap.Config.RGB_565, true); +// FaceDetector.Face[] faces = new FaceDetector.Face[1]; +// FaceDetector faceDetector = new FaceDetector(faceDetectorBitmap.getWidth(), faceDetectorBitmap.getHeight(), 1); +// int faceSum = faceDetector.findFaces(faceDetectorBitmap, faces); +// if (faceSum == 1) { + bitmapStack.push(originBitmap); + if (bitmapStack.size() >= 5) {//当栈里有5张bitmap之后才开始识别 + if (isCanLogin) { + isCanLogin = false; + Bitmap bitmap = bitmapStack.pop(); + Intent intent = new Intent(); + intent.putExtra("imageToBase64", ImageHelper.imageToBase64(bitmap)); + setResult(Activity.RESULT_OK, intent); + finish(); + } else { + finish(); + } + } +// } else { +// Log.d(TAG, "detectorFace: 未检测到人脸"); +// } + } + + /** + * 打开相机 + */ + private void openCamera() { + try { + mCamera = Camera.open(1); + initParameters(mCamera); //初始化相机配置信息 + mCamera.setPreviewCallback(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化相机属性 + */ + private void initParameters(Camera camera) { + try { + Camera.Parameters mParameters = camera.getParameters(); + mParameters.setPreviewFormat(ImageFormat.NV21); //设置预览图片的格式 + //获取与指定宽高相等或最接近的尺寸 + //设置预览尺寸 + Camera.Size bestPreviewSize = obtainBestSize(preViewWidth, preViewHeight, mParameters.getSupportedPreviewSizes()); + mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height); + //设置保存图片尺寸 +// Camera.Size bestPicSize = obtainBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes()); +// mParameters.setPictureSize(bestPicSize.width, bestPicSize.height); + //对焦模式 + mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + camera.setDisplayOrientation(90); + camera.setParameters(mParameters); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取最合适的尺寸 + */ + private Camera.Size obtainBestSize(int targetWidth, int targetHeight, List sizeList) { + Camera.Size bestSize = null; + int targetRatio = targetHeight / targetWidth;//目标大小的宽高比 + int minDiff = targetRatio; + + for (Camera.Size size : sizeList) { + if (size.width == targetHeight && size.height == targetWidth) { + bestSize = size; + break; + } + int supportedRatio = (size.width / size.height); + if (Math.abs(supportedRatio - targetRatio) < minDiff) { + minDiff = Math.abs(supportedRatio - targetRatio); + bestSize = size; + } + } + return bestSize; + } + + /** + * 释放相机资源 + */ + private void releaseCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java index 98aef9d..30c26c8 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java @@ -8,14 +8,15 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.Nullable; import com.casic.birmm.hxrq.R; -import com.casic.birmm.hxrq.base.DoubleClickExitActivity; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -28,23 +29,16 @@ import com.casic.birmm.hxrq.mvp.view.IFaceLoginView; import com.casic.birmm.hxrq.mvp.view.ILoginView; import com.casic.birmm.hxrq.mvp.view.IQrCodeDataView; -import com.casic.birmm.hxrq.utils.FileUtils; -import com.casic.birmm.hxrq.utils.GlideLoadEngine; +import com.casic.birmm.hxrq.utils.Constant; import com.casic.birmm.hxrq.utils.RSAUtils; import com.casic.birmm.hxrq.utils.SaveKeyValues; -import com.casic.birmm.hxrq.utils.StringHelper; import com.casic.birmm.hxrq.utils.TokenHelper; import com.google.gson.Gson; -import com.luck.picture.lib.PictureSelector; -import com.luck.picture.lib.config.PictureConfig; -import com.luck.picture.lib.config.PictureMimeType; -import com.luck.picture.lib.entity.LocalMedia; import com.qmuiteam.qmui.util.QMUIStatusBarHelper; import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUITipDialog; import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton; -import java.io.File; import java.security.PublicKey; import butterknife.BindView; @@ -53,15 +47,11 @@ import cn.bertsir.zbar.QrConfig; import cn.bertsir.zbar.QrManager; import cn.bertsir.zbar.view.ScanLineView; -import top.zibin.luban.CompressionPredicate; -import top.zibin.luban.Luban; -import top.zibin.luban.OnCompressListener; -public class LoginActivity extends DoubleClickExitActivity - implements View.OnClickListener, IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { +public class LoginActivity extends BaseActivity implements View.OnClickListener, + IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { private static final String TAG = "LoginActivity"; - @BindView(R.id.userNameView) EditText userNameView; @BindView(R.id.userPasswordView) @@ -76,8 +66,8 @@ private LoginPresenterImpl loginPresenter; private QrCodePresenterImpl qrCodePresenter; private FaceLoginPresenterImpl faceLoginPresenter; - private String userName; - private String userPassword; + private boolean isPasswordLogin = false; + private String qrCode = ""; @Override public int initLayoutView() { @@ -86,20 +76,29 @@ @Override protected void setupTopBarLayout() { - //TODO 此页面无需实现 + //设置状态栏黑色字体图标 + QMUIStatusBarHelper.setStatusBarLightMode(this); } @Override public void initData() { - //设置状态栏黑色字体图标 - QMUIStatusBarHelper.setStatusBarLightMode(this); - String userName = (String) SaveKeyValues.getValue("userName", ""); String userPassword = (String) SaveKeyValues.getValue("userPassword", ""); + userNameView.setText(userName); + userPasswordView.setText(userPassword); if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(userPassword)) { - userNameView.setText(userName); - userPasswordView.setText(userPassword); + rememberPasswordView.setChecked(true); + } else { + rememberPasswordView.setChecked(false); } + rememberPasswordView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!isChecked) { + SaveKeyValues.removeKey("userPassword"); + } + } + }); loadingDialog = new QMUITipDialog.Builder(this) .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING) .setTipWord("登陆中,请稍后") @@ -124,14 +123,9 @@ public void onClick(View v) { switch (v.getId()) { case R.id.loginButton: - userName = userNameView.getText().toString(); - userPassword = userPasswordView.getText().toString(); - if (rememberPasswordView.isChecked()) { - SaveKeyValues.putValue("userName", userName); - SaveKeyValues.putValue("userPassword", userPassword); - } //密码登录前需要验证sid authenticatePresenter.onReadyRetrofitRequest(); + isPasswordLogin = true; break; case R.id.changeLoginModeView: //首次登录不可用扫码,因为还未注册 @@ -169,50 +163,19 @@ } private void captureFaceData() { - //TODO 调相机,捕获人脸数据,并保存为文件得到路径 - PictureSelector.create(this) - .openCamera(PictureMimeType.ofImage()) - .imageEngine(GlideLoadEngine.createGlideEngine()) - .maxSelectNum(1) - .forResult(PictureConfig.REQUEST_CAMERA); + // 调相机,捕获人脸数据,并保存为文件得到路径 + startActivityForResult(new Intent(this, FacePreViewActivity.class), Constant.FACE_DETECTOR_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - if (requestCode == PictureConfig.REQUEST_CAMERA) { - LocalMedia localMedia = PictureSelector.obtainMultipleResult(data).get(0); - Luban.with(this) - .load(localMedia.getRealPath()) - .ignoreBy(100) - .setTargetDir(FileUtils.getFileDir("CompressImageFile")) - .filter(new CompressionPredicate() { - @Override - public boolean apply(String path) { - return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif")); - } - }) - .setCompressListener(new OnCompressListener() { - @Override - public void onStart() { - // TODO 压缩开始前调用,可以在方法内启动 loading UI - } - - @Override - public void onSuccess(File file) { - String imageToBase64 = StringHelper.imageToBase64(file); - - ImageBean imageBean = new ImageBean(); - imageBean.setImage(imageToBase64); - faceLoginPresenter.onReadyRetrofitRequest(imageBean); - } - - @Override - public void onError(Throwable e) { - // TODO 当压缩过程出现问题时调用 - } - }).launch(); + if (requestCode == Constant.FACE_DETECTOR_CODE) { + String imageToBase64 = data.getStringExtra("imageToBase64"); + ImageBean imageBean = new ImageBean(); + imageBean.setImage(imageToBase64); + faceLoginPresenter.onReadyRetrofitRequest(imageBean); } } } @@ -232,7 +195,7 @@ .setPlaySound(true)//是否扫描成功后bi~的声音 .setDingPath(R.raw.qrcode)//设置提示音(不设置为默认的Ding~) .setIsOnlyCenter(true)//是否只识别框中内容(默认为全屏识别) - .setTitleBackgroudColor(Color.parseColor("#262020"))//设置状态栏颜色 + .setTitleBackgroudColor(R.color.black)//设置状态栏颜色 .setTitleTextColor(Color.WHITE)//设置Title文字颜色 .setScreenOrientation(QrConfig.SCREEN_PORTRAIT)//设置屏幕方式 .setScanLineStyle(ScanLineView.style_hybrid)//扫描线样式 @@ -241,8 +204,8 @@ QrManager.getInstance().init(qrConfig).startScan(this, new QrManager.OnScanResultCallback() { @Override public void onScanSuccess(final ScanResult result) { -// Log.d(TAG, "扫码结果: " + result.content); - qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), result.content); + qrCode = result.content; + authenticatePresenter.onReadyRetrofitRequest();//需要时时保持最新token,所以扫码登录之前需要获取最新token } }); } @@ -254,9 +217,15 @@ @Override public void authenticateResult(PublicKeyBean result) { - Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); +// Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); if (result.isSuccess()) { PublicKey publicKey = RSAUtils.keyStrToPublicKey(result.getData().getPublicKey()); + String userName = userNameView.getText().toString(); + String userPassword = userPasswordView.getText().toString(); + if (rememberPasswordView.isChecked()) { + SaveKeyValues.putValue("userName", userName); + SaveKeyValues.putValue("userPassword", userPassword); + } if (TextUtils.isEmpty(userName)) { Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show(); return; @@ -266,7 +235,6 @@ return; } String dataByPublicKey = RSAUtils.encryptDataByPublicKey(userPassword.getBytes(), publicKey); - Log.d(TAG, "authenticateResult: 验证成功,开始登录"); //登录并获取Token,POST请求 loginPresenter.onReadyRetrofitRequest(result.getData().getSid(), userName, dataByPublicKey); } else { @@ -283,11 +251,14 @@ String token = result.getData().getToken(); if (!TextUtils.isEmpty(token)) { //获取用户信息 - Log.d(TAG, "obtainLoginResult: 获取Token成功"); TokenHelper.saveToken(token); //验证成功登录 - startActivity(new Intent(this, MainActivity.class)); - finish(); + if (isPasswordLogin) { + startActivity(new Intent(this, MainActivity.class)); + finish(); + } else { + qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), qrCode); + } } } @@ -307,15 +278,17 @@ } @Override - public void obtainFaceLoginData(FaceLoginResultBean resultBean) { -// Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); - if (resultBean.getCode() == 200) { + public void obtainFaceLoginData(FaceResultBean resultBean) { + Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); + if (resultBean.isSuccess()) { + //{"code":200,"data":{"kaptcha":"","token":"9135bcb7-4f39-4b7a-a10e-555406ddb9e1"},"exceptionClazz":"","message":"登录成功","success":true} TokenHelper.saveToken(resultBean.getData().getToken()); //验证成功登录 startActivity(new Intent(this, MainActivity.class)); finish(); } else { - Toast.makeText(this, "无法解析人脸", Toast.LENGTH_SHORT).show(); + //{"code":200,"data":"","exceptionClazz":"","message":"图片中没有人脸","success":false} + Toast.makeText(this, "人脸识别失败", Toast.LENGTH_SHORT).show(); } } @@ -336,5 +309,8 @@ if (qrCodePresenter != null) { qrCodePresenter.disposeRetrofitRequest(); } + if (faceLoginPresenter != null) { + faceLoginPresenter.disposeRetrofitRequest(); + } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java index e8e9b75..759a94d 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java @@ -9,4 +9,5 @@ Manifest.permission.WRITE_EXTERNAL_STORAGE}; public static final int PERMISSIONS_CODE = 999; + public static final int FACE_DETECTOR_CODE = 998; } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java new file mode 100644 index 0000000..b774ee9 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java @@ -0,0 +1,95 @@ +package com.casic.birmm.hxrq.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.ImageFormat; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.YuvImage; +import android.util.Base64; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class ImageHelper { + + public ImageHelper(Context context) { + + } + + public Bitmap nv21ToBitmap(byte[] nv21, int width, int height) { + Bitmap bitmap = null; + try { + final YuvImage image = new YuvImage(nv21, ImageFormat.NV21, width, height, null); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + image.compressToJpeg(new Rect(0, 0, width, height), 80, outputStream); + final Bitmap bmp = BitmapFactory.decodeByteArray(outputStream.toByteArray(), 0, outputStream.size()); + bitmap = rotateImageView(-90, bmp); + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return bitmap; + } + + public Bitmap rotateImageView(int angle, Bitmap bitmap) { + //旋转图片 动作 + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + // 创建新的图片 + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(File file) { + if (file == null) { + return null; + } + try { + FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int n; + while ((n = fis.read(b)) != -1) { + bos.write(b, 0, n); + } + fis.close(); + bos.close(); + + byte[] imgBytes = bos.toByteArray(); + String result = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (Exception e) { + return null; + } + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);//压缩质量 + + outputStream.flush(); + outputStream.close(); + + byte[] bitmapBytes = outputStream.toByteArray(); + String result = Base64.encodeToString(bitmapBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (IOException e) { + return null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java index f4af6a5..e7772dd 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java @@ -3,33 +3,26 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; -import android.util.Log; public class SaveKeyValues { - private static final String TAG = "SaveKeyValues"; - - @SuppressLint({"StaticFieldLeak"}) - private static Context context; private static SharedPreferences sharedPreferences; private static SharedPreferences.Editor editor; - private static String fileName; + @SuppressLint("CommitPrefEdits") public static void initSharedPreferences(Context mContext) { - context = mContext.getApplicationContext(); - String packageName = context.getPackageName(); + String packageName = mContext.getPackageName(); //获取到的包名带有“.”方便命名,取最后一个作为sp文件名,例如:com.casic.dcms String[] split = packageName.split("\\.");//先转义.之后才能分割 int length = split.length; - fileName = split[length - 1]; - Log.d(TAG, fileName); + String fileName = split[length - 1]; + sharedPreferences = mContext.getSharedPreferences(fileName, Context.MODE_PRIVATE); + editor = sharedPreferences.edit(); } /** * 存储 */ public static void putValue(String key, Object object) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); - editor = sharedPreferences.edit(); if (object instanceof String) { editor.putString(key, (String) object); } else if (object instanceof Integer) { @@ -50,7 +43,6 @@ * 获取保存的数据 */ public static Object getValue(String key, Object defaultObject) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); if (defaultObject instanceof String) { return sharedPreferences.getString(key, (String) defaultObject); } else if (defaultObject instanceof Integer) { @@ -86,7 +78,6 @@ * 查询某个key是否存在 */ public static boolean containsKey(String key) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); return sharedPreferences.contains(key); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java deleted file mode 100644 index 0ebf16a..0000000 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.casic.birmm.hxrq.utils; - -import android.util.Base64; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; - -/** - * @Author: Pengxh - * @Time: 2021/4/9 15:12 - * @Email: 290677893@qq.com - **/ -public class StringHelper { - /** - * 获取图片base64编码 - */ - public static String imageToBase64(File file) { - if (file == null) { - return null; - } - try { - FileInputStream fis = new FileInputStream(file); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] b = new byte[1024]; - int n; - while ((n = fis.read(b)) != -1) { - bos.write(b, 0, n); - } - fis.close(); - bos.close(); - - byte[] imgBytes = bos.toByteArray(); - String s = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); - return s.replace("-", "+") - .replace("_", "/"); - } catch (Exception e) { - return null; - } - } -} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java index 8fe5264..1de1ff4 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.utils.retrofit; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -49,6 +49,6 @@ */ @Headers({"Content-Type: application/json"}) @POST("/cockpit/face/login") - Observable getFaceLoginResult( + Observable getFaceLoginResult( @Body ImageBean imageBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java index ef4307e..d481055 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java @@ -2,7 +2,7 @@ import android.util.Log; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -10,7 +10,6 @@ import com.casic.birmm.hxrq.utils.HttpConfig; import org.jetbrains.annotations.NotNull; -import org.json.JSONObject; import java.util.concurrent.TimeUnit; @@ -79,7 +78,7 @@ /** * 人脸识别登录结果 */ - public static Observable getFaceResult(String baseUrl, ImageBean imageBean) { + public static Observable getFaceResult(String baseUrl, ImageBean imageBean) { Retrofit retrofit = createRetrofit(baseUrl); RetrofitService service = retrofit.create(RetrofitService.class); return service.getFaceLoginResult(imageBean); diff --git a/app/src/main/res/drawable/bg_circle_image.xml b/app/src/main/res/drawable/bg_circle_image.xml new file mode 100644 index 0000000..5b27ca4 --- /dev/null +++ b/app/src/main/res/drawable/bg_circle_image.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_face.xml b/app/src/main/res/layout/activity_face.xml new file mode 100644 index 0000000..0d2e4e0 --- /dev/null +++ b/app/src/main/res/layout/activity_face.xml @@ -0,0 +1,25 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index b300663..5e16fcb 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -74,8 +74,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/loginButton" - android:layout_marginTop="20dp" android:gravity="center" + android:paddingVertical="20dp" android:text="换个方式登录" android:textColor="@color/mainThemeColor" android:textSize="@dimen/textFontSize" /> diff --git a/app/build.gradle b/app/build.gradle index 9d60011..5577e3b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -30,8 +30,7 @@ dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.0.2' - implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'androidx.appcompat:appcompat:1.2.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' @@ -60,6 +59,4 @@ implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0' //图片加载框架 implementation 'com.github.bumptech.glide:glide:4.5.0' - //图片压缩框架 - implementation 'top.zibin:Luban:1.1.8' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6065dc..dceb8c3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,8 @@ + + @@ -29,6 +31,7 @@ + observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); - return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { + Observable observable = RetrofitServiceManager.getFaceResult(HttpConfig.BASE_IP, image); + return observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer() { @Override public void onCompleted() { @@ -50,7 +50,7 @@ } @Override - public void onNext(FaceLoginResultBean resultBean) { + public void onNext(FaceResultBean resultBean) { if (resultBean != null) { listener.onSuccess(resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java index aac04d9..c9e56be 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/AuthenticatePresenterImpl.java @@ -29,10 +29,12 @@ @Override public void onSuccess(PublicKeyBean resultBean) { + view.hideProgress(); view.authenticateResult(resultBean); } @Override public void onFailure(Throwable throwable) { + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java index 7fb154c..d4b110f 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/FaceLoginPresenterImpl.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.mvp.presenter; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.mvp.BasePresenter; import com.casic.birmm.hxrq.mvp.model.FaceLoginModelImpl; @@ -23,6 +23,7 @@ @Override public void onReadyRetrofitRequest(ImageBean image) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(image)); } @@ -33,12 +34,13 @@ @Override - public void onSuccess(FaceLoginResultBean resultBean) { + public void onSuccess(FaceResultBean resultBean) { + view.hideProgress(); view.obtainFaceLoginData(resultBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java index 44cd8a7..31d88bf 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/LoginPresenterImpl.java @@ -18,6 +18,7 @@ @Override public void onReadyRetrofitRequest(String sid, String username, String key) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(sid, username, key)); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java index be065db..071a285 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/presenter/QrCodePresenterImpl.java @@ -17,6 +17,7 @@ @Override public void onReadyRetrofitRequest(String token, String qrcodeId) { + view.showProgress(); addSubscription(actionModel.sendRetrofitRequest(token, qrcodeId)); } @@ -27,11 +28,12 @@ @Override public void onSuccess(QrCodeBean codeBean) { + view.hideProgress(); view.obtainQrCodeData(codeBean); } @Override public void onFailure(Throwable throwable) { - + view.hideProgress(); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java index 2936b0a..4d8e949 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IAuthenticateView.java @@ -9,5 +9,7 @@ public interface IAuthenticateView { void showProgress(); + void hideProgress(); + void authenticateResult(PublicKeyBean result); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java index c6d3e33..7e502f2 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IFaceLoginView.java @@ -1,7 +1,11 @@ package com.casic.birmm.hxrq.mvp.view; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; public interface IFaceLoginView { - void obtainFaceLoginData(FaceLoginResultBean resultBean); + void showProgress(); + + void hideProgress(); + + void obtainFaceLoginData(FaceResultBean resultBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java index c9783cd..fe666b1 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/ILoginView.java @@ -3,6 +3,8 @@ import com.casic.birmm.hxrq.bean.LoginResultBean; public interface ILoginView { + void showProgress(); + void hideProgress(); void obtainLoginResult(LoginResultBean resultBean); diff --git a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java index 4e8821e..4003e26 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java +++ b/app/src/main/java/com/casic/birmm/hxrq/mvp/view/IQrCodeDataView.java @@ -3,5 +3,9 @@ import com.casic.birmm.hxrq.bean.QrCodeBean; public interface IQrCodeDataView { + void showProgress(); + + void hideProgress(); + void obtainQrCodeData(QrCodeBean userBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java new file mode 100644 index 0000000..4109e3c --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/FacePreViewActivity.java @@ -0,0 +1,184 @@ +package com.casic.birmm.hxrq.ui; + +import android.app.Activity; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.ImageFormat; +import android.hardware.Camera; +import android.view.SurfaceHolder; +import android.view.SurfaceView; + +import androidx.annotation.NonNull; + +import com.casic.birmm.hxrq.R; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.utils.ImageHelper; + +import java.io.IOException; +import java.util.List; +import java.util.Stack; + +import butterknife.BindView; + +public class FacePreViewActivity extends BaseActivity implements Camera.PreviewCallback { + + private static final int preViewWidth = 720; + private static final int preViewHeight = 1280; + @BindView(R.id.surfaceView) + SurfaceView surfaceView; + private SurfaceHolder mSurfaceHolder; + private Camera mCamera; + private ImageHelper imageHelper; + private Stack bitmapStack; + private boolean isCanLogin = true; + + @Override + public int initLayoutView() { + return R.layout.activity_face; + } + + @Override + protected void setupTopBarLayout() { + + } + + @Override + public void initData() { + imageHelper = new ImageHelper(this); + bitmapStack = new Stack<>(); + } + + @Override + public void initEvent() { + // 绑定SurfaceView,取得SurfaceHolder对象 + mSurfaceHolder = surfaceView.getHolder(); + mSurfaceHolder.addCallback(new SurfaceHolder.Callback() { + @Override + public void surfaceCreated(@NonNull SurfaceHolder holder) { + if (mCamera == null) { + //打开相机 + openCamera(); + } + try { + //预览画面 + mCamera.setPreviewDisplay(mSurfaceHolder); + } catch (IOException e) { + e.printStackTrace(); + } + //开始预览 + mCamera.startPreview(); + } + + @Override + public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) { + + } + + @Override + public void surfaceDestroyed(@NonNull SurfaceHolder holder) { + releaseCamera(); //释放相机资源 + } + }); + mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置 + } + + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + camera.addCallbackBuffer(data); + Camera.Size size = camera.getParameters().getPreviewSize();//必须是相机支持的预览尺寸,否则颜色YUV空间会错位 + Bitmap originBitmap = imageHelper.nv21ToBitmap(data, size.width, size.height); + //要使用Android内置的人脸识别,需要将Bitmap对象转为RGB_565格式,否则无法识别 +// Bitmap faceDetectorBitmap = originBitmap.copy(Bitmap.Config.RGB_565, true); +// FaceDetector.Face[] faces = new FaceDetector.Face[1]; +// FaceDetector faceDetector = new FaceDetector(faceDetectorBitmap.getWidth(), faceDetectorBitmap.getHeight(), 1); +// int faceSum = faceDetector.findFaces(faceDetectorBitmap, faces); +// if (faceSum == 1) { + bitmapStack.push(originBitmap); + if (bitmapStack.size() >= 5) {//当栈里有5张bitmap之后才开始识别 + if (isCanLogin) { + isCanLogin = false; + Bitmap bitmap = bitmapStack.pop(); + Intent intent = new Intent(); + intent.putExtra("imageToBase64", ImageHelper.imageToBase64(bitmap)); + setResult(Activity.RESULT_OK, intent); + finish(); + } else { + finish(); + } + } +// } else { +// Log.d(TAG, "detectorFace: 未检测到人脸"); +// } + } + + /** + * 打开相机 + */ + private void openCamera() { + try { + mCamera = Camera.open(1); + initParameters(mCamera); //初始化相机配置信息 + mCamera.setPreviewCallback(this); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 初始化相机属性 + */ + private void initParameters(Camera camera) { + try { + Camera.Parameters mParameters = camera.getParameters(); + mParameters.setPreviewFormat(ImageFormat.NV21); //设置预览图片的格式 + //获取与指定宽高相等或最接近的尺寸 + //设置预览尺寸 + Camera.Size bestPreviewSize = obtainBestSize(preViewWidth, preViewHeight, mParameters.getSupportedPreviewSizes()); + mParameters.setPreviewSize(bestPreviewSize.width, bestPreviewSize.height); + //设置保存图片尺寸 +// Camera.Size bestPicSize = obtainBestSize(picWidth, picHeight, mParameters.getSupportedPictureSizes()); +// mParameters.setPictureSize(bestPicSize.width, bestPicSize.height); + //对焦模式 + mParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); + camera.setDisplayOrientation(90); + camera.setParameters(mParameters); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 获取最合适的尺寸 + */ + private Camera.Size obtainBestSize(int targetWidth, int targetHeight, List sizeList) { + Camera.Size bestSize = null; + int targetRatio = targetHeight / targetWidth;//目标大小的宽高比 + int minDiff = targetRatio; + + for (Camera.Size size : sizeList) { + if (size.width == targetHeight && size.height == targetWidth) { + bestSize = size; + break; + } + int supportedRatio = (size.width / size.height); + if (Math.abs(supportedRatio - targetRatio) < minDiff) { + minDiff = Math.abs(supportedRatio - targetRatio); + bestSize = size; + } + } + return bestSize; + } + + /** + * 释放相机资源 + */ + private void releaseCamera() { + if (mCamera != null) { + mCamera.stopPreview(); + mCamera.setPreviewCallback(null); + mCamera.release(); + mCamera = null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java index 98aef9d..30c26c8 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java +++ b/app/src/main/java/com/casic/birmm/hxrq/ui/LoginActivity.java @@ -8,14 +8,15 @@ import android.util.Log; import android.view.View; import android.widget.CheckBox; +import android.widget.CompoundButton; import android.widget.EditText; import android.widget.Toast; import androidx.annotation.Nullable; import com.casic.birmm.hxrq.R; -import com.casic.birmm.hxrq.base.DoubleClickExitActivity; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.base.BaseActivity; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -28,23 +29,16 @@ import com.casic.birmm.hxrq.mvp.view.IFaceLoginView; import com.casic.birmm.hxrq.mvp.view.ILoginView; import com.casic.birmm.hxrq.mvp.view.IQrCodeDataView; -import com.casic.birmm.hxrq.utils.FileUtils; -import com.casic.birmm.hxrq.utils.GlideLoadEngine; +import com.casic.birmm.hxrq.utils.Constant; import com.casic.birmm.hxrq.utils.RSAUtils; import com.casic.birmm.hxrq.utils.SaveKeyValues; -import com.casic.birmm.hxrq.utils.StringHelper; import com.casic.birmm.hxrq.utils.TokenHelper; import com.google.gson.Gson; -import com.luck.picture.lib.PictureSelector; -import com.luck.picture.lib.config.PictureConfig; -import com.luck.picture.lib.config.PictureMimeType; -import com.luck.picture.lib.entity.LocalMedia; import com.qmuiteam.qmui.util.QMUIStatusBarHelper; import com.qmuiteam.qmui.widget.dialog.QMUIDialog; import com.qmuiteam.qmui.widget.dialog.QMUITipDialog; import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton; -import java.io.File; import java.security.PublicKey; import butterknife.BindView; @@ -53,15 +47,11 @@ import cn.bertsir.zbar.QrConfig; import cn.bertsir.zbar.QrManager; import cn.bertsir.zbar.view.ScanLineView; -import top.zibin.luban.CompressionPredicate; -import top.zibin.luban.Luban; -import top.zibin.luban.OnCompressListener; -public class LoginActivity extends DoubleClickExitActivity - implements View.OnClickListener, IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { +public class LoginActivity extends BaseActivity implements View.OnClickListener, + IAuthenticateView, ILoginView, IQrCodeDataView, IFaceLoginView { private static final String TAG = "LoginActivity"; - @BindView(R.id.userNameView) EditText userNameView; @BindView(R.id.userPasswordView) @@ -76,8 +66,8 @@ private LoginPresenterImpl loginPresenter; private QrCodePresenterImpl qrCodePresenter; private FaceLoginPresenterImpl faceLoginPresenter; - private String userName; - private String userPassword; + private boolean isPasswordLogin = false; + private String qrCode = ""; @Override public int initLayoutView() { @@ -86,20 +76,29 @@ @Override protected void setupTopBarLayout() { - //TODO 此页面无需实现 + //设置状态栏黑色字体图标 + QMUIStatusBarHelper.setStatusBarLightMode(this); } @Override public void initData() { - //设置状态栏黑色字体图标 - QMUIStatusBarHelper.setStatusBarLightMode(this); - String userName = (String) SaveKeyValues.getValue("userName", ""); String userPassword = (String) SaveKeyValues.getValue("userPassword", ""); + userNameView.setText(userName); + userPasswordView.setText(userPassword); if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(userPassword)) { - userNameView.setText(userName); - userPasswordView.setText(userPassword); + rememberPasswordView.setChecked(true); + } else { + rememberPasswordView.setChecked(false); } + rememberPasswordView.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!isChecked) { + SaveKeyValues.removeKey("userPassword"); + } + } + }); loadingDialog = new QMUITipDialog.Builder(this) .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING) .setTipWord("登陆中,请稍后") @@ -124,14 +123,9 @@ public void onClick(View v) { switch (v.getId()) { case R.id.loginButton: - userName = userNameView.getText().toString(); - userPassword = userPasswordView.getText().toString(); - if (rememberPasswordView.isChecked()) { - SaveKeyValues.putValue("userName", userName); - SaveKeyValues.putValue("userPassword", userPassword); - } //密码登录前需要验证sid authenticatePresenter.onReadyRetrofitRequest(); + isPasswordLogin = true; break; case R.id.changeLoginModeView: //首次登录不可用扫码,因为还未注册 @@ -169,50 +163,19 @@ } private void captureFaceData() { - //TODO 调相机,捕获人脸数据,并保存为文件得到路径 - PictureSelector.create(this) - .openCamera(PictureMimeType.ofImage()) - .imageEngine(GlideLoadEngine.createGlideEngine()) - .maxSelectNum(1) - .forResult(PictureConfig.REQUEST_CAMERA); + // 调相机,捕获人脸数据,并保存为文件得到路径 + startActivityForResult(new Intent(this, FacePreViewActivity.class), Constant.FACE_DETECTOR_CODE); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { - if (requestCode == PictureConfig.REQUEST_CAMERA) { - LocalMedia localMedia = PictureSelector.obtainMultipleResult(data).get(0); - Luban.with(this) - .load(localMedia.getRealPath()) - .ignoreBy(100) - .setTargetDir(FileUtils.getFileDir("CompressImageFile")) - .filter(new CompressionPredicate() { - @Override - public boolean apply(String path) { - return !(TextUtils.isEmpty(path) || path.toLowerCase().endsWith(".gif")); - } - }) - .setCompressListener(new OnCompressListener() { - @Override - public void onStart() { - // TODO 压缩开始前调用,可以在方法内启动 loading UI - } - - @Override - public void onSuccess(File file) { - String imageToBase64 = StringHelper.imageToBase64(file); - - ImageBean imageBean = new ImageBean(); - imageBean.setImage(imageToBase64); - faceLoginPresenter.onReadyRetrofitRequest(imageBean); - } - - @Override - public void onError(Throwable e) { - // TODO 当压缩过程出现问题时调用 - } - }).launch(); + if (requestCode == Constant.FACE_DETECTOR_CODE) { + String imageToBase64 = data.getStringExtra("imageToBase64"); + ImageBean imageBean = new ImageBean(); + imageBean.setImage(imageToBase64); + faceLoginPresenter.onReadyRetrofitRequest(imageBean); } } } @@ -232,7 +195,7 @@ .setPlaySound(true)//是否扫描成功后bi~的声音 .setDingPath(R.raw.qrcode)//设置提示音(不设置为默认的Ding~) .setIsOnlyCenter(true)//是否只识别框中内容(默认为全屏识别) - .setTitleBackgroudColor(Color.parseColor("#262020"))//设置状态栏颜色 + .setTitleBackgroudColor(R.color.black)//设置状态栏颜色 .setTitleTextColor(Color.WHITE)//设置Title文字颜色 .setScreenOrientation(QrConfig.SCREEN_PORTRAIT)//设置屏幕方式 .setScanLineStyle(ScanLineView.style_hybrid)//扫描线样式 @@ -241,8 +204,8 @@ QrManager.getInstance().init(qrConfig).startScan(this, new QrManager.OnScanResultCallback() { @Override public void onScanSuccess(final ScanResult result) { -// Log.d(TAG, "扫码结果: " + result.content); - qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), result.content); + qrCode = result.content; + authenticatePresenter.onReadyRetrofitRequest();//需要时时保持最新token,所以扫码登录之前需要获取最新token } }); } @@ -254,9 +217,15 @@ @Override public void authenticateResult(PublicKeyBean result) { - Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); +// Log.d(TAG, "authenticateResult: " + new Gson().toJson(result)); if (result.isSuccess()) { PublicKey publicKey = RSAUtils.keyStrToPublicKey(result.getData().getPublicKey()); + String userName = userNameView.getText().toString(); + String userPassword = userPasswordView.getText().toString(); + if (rememberPasswordView.isChecked()) { + SaveKeyValues.putValue("userName", userName); + SaveKeyValues.putValue("userPassword", userPassword); + } if (TextUtils.isEmpty(userName)) { Toast.makeText(this, "用户名不能为空", Toast.LENGTH_SHORT).show(); return; @@ -266,7 +235,6 @@ return; } String dataByPublicKey = RSAUtils.encryptDataByPublicKey(userPassword.getBytes(), publicKey); - Log.d(TAG, "authenticateResult: 验证成功,开始登录"); //登录并获取Token,POST请求 loginPresenter.onReadyRetrofitRequest(result.getData().getSid(), userName, dataByPublicKey); } else { @@ -283,11 +251,14 @@ String token = result.getData().getToken(); if (!TextUtils.isEmpty(token)) { //获取用户信息 - Log.d(TAG, "obtainLoginResult: 获取Token成功"); TokenHelper.saveToken(token); //验证成功登录 - startActivity(new Intent(this, MainActivity.class)); - finish(); + if (isPasswordLogin) { + startActivity(new Intent(this, MainActivity.class)); + finish(); + } else { + qrCodePresenter.onReadyRetrofitRequest(TokenHelper.getToken(), qrCode); + } } } @@ -307,15 +278,17 @@ } @Override - public void obtainFaceLoginData(FaceLoginResultBean resultBean) { -// Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); - if (resultBean.getCode() == 200) { + public void obtainFaceLoginData(FaceResultBean resultBean) { + Log.d(TAG, "obtainFaceLoginData: " + new Gson().toJson(resultBean)); + if (resultBean.isSuccess()) { + //{"code":200,"data":{"kaptcha":"","token":"9135bcb7-4f39-4b7a-a10e-555406ddb9e1"},"exceptionClazz":"","message":"登录成功","success":true} TokenHelper.saveToken(resultBean.getData().getToken()); //验证成功登录 startActivity(new Intent(this, MainActivity.class)); finish(); } else { - Toast.makeText(this, "无法解析人脸", Toast.LENGTH_SHORT).show(); + //{"code":200,"data":"","exceptionClazz":"","message":"图片中没有人脸","success":false} + Toast.makeText(this, "人脸识别失败", Toast.LENGTH_SHORT).show(); } } @@ -336,5 +309,8 @@ if (qrCodePresenter != null) { qrCodePresenter.disposeRetrofitRequest(); } + if (faceLoginPresenter != null) { + faceLoginPresenter.disposeRetrofitRequest(); + } } -} +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java index e8e9b75..759a94d 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/Constant.java @@ -9,4 +9,5 @@ Manifest.permission.WRITE_EXTERNAL_STORAGE}; public static final int PERMISSIONS_CODE = 999; + public static final int FACE_DETECTOR_CODE = 998; } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java new file mode 100644 index 0000000..b774ee9 --- /dev/null +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/ImageHelper.java @@ -0,0 +1,95 @@ +package com.casic.birmm.hxrq.utils; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.ImageFormat; +import android.graphics.Matrix; +import android.graphics.Rect; +import android.graphics.YuvImage; +import android.util.Base64; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +public class ImageHelper { + + public ImageHelper(Context context) { + + } + + public Bitmap nv21ToBitmap(byte[] nv21, int width, int height) { + Bitmap bitmap = null; + try { + final YuvImage image = new YuvImage(nv21, ImageFormat.NV21, width, height, null); + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + image.compressToJpeg(new Rect(0, 0, width, height), 80, outputStream); + final Bitmap bmp = BitmapFactory.decodeByteArray(outputStream.toByteArray(), 0, outputStream.size()); + bitmap = rotateImageView(-90, bmp); + outputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return bitmap; + } + + public Bitmap rotateImageView(int angle, Bitmap bitmap) { + //旋转图片 动作 + Matrix matrix = new Matrix(); + matrix.postRotate(angle); + // 创建新的图片 + return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(File file) { + if (file == null) { + return null; + } + try { + FileInputStream fis = new FileInputStream(file); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] b = new byte[1024]; + int n; + while ((n = fis.read(b)) != -1) { + bos.write(b, 0, n); + } + fis.close(); + bos.close(); + + byte[] imgBytes = bos.toByteArray(); + String result = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (Exception e) { + return null; + } + } + + /** + * 获取图片base64编码 + */ + public static String imageToBase64(Bitmap bitmap) { + if (bitmap == null) { + return null; + } + try { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + bitmap.compress(Bitmap.CompressFormat.JPEG, 80, outputStream);//压缩质量 + + outputStream.flush(); + outputStream.close(); + + byte[] bitmapBytes = outputStream.toByteArray(); + String result = Base64.encodeToString(bitmapBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); + return result.replace("-", "+") + .replace("_", "/"); + } catch (IOException e) { + return null; + } + } +} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java index f4af6a5..e7772dd 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/SaveKeyValues.java @@ -3,33 +3,26 @@ import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; -import android.util.Log; public class SaveKeyValues { - private static final String TAG = "SaveKeyValues"; - - @SuppressLint({"StaticFieldLeak"}) - private static Context context; private static SharedPreferences sharedPreferences; private static SharedPreferences.Editor editor; - private static String fileName; + @SuppressLint("CommitPrefEdits") public static void initSharedPreferences(Context mContext) { - context = mContext.getApplicationContext(); - String packageName = context.getPackageName(); + String packageName = mContext.getPackageName(); //获取到的包名带有“.”方便命名,取最后一个作为sp文件名,例如:com.casic.dcms String[] split = packageName.split("\\.");//先转义.之后才能分割 int length = split.length; - fileName = split[length - 1]; - Log.d(TAG, fileName); + String fileName = split[length - 1]; + sharedPreferences = mContext.getSharedPreferences(fileName, Context.MODE_PRIVATE); + editor = sharedPreferences.edit(); } /** * 存储 */ public static void putValue(String key, Object object) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); - editor = sharedPreferences.edit(); if (object instanceof String) { editor.putString(key, (String) object); } else if (object instanceof Integer) { @@ -50,7 +43,6 @@ * 获取保存的数据 */ public static Object getValue(String key, Object defaultObject) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); if (defaultObject instanceof String) { return sharedPreferences.getString(key, (String) defaultObject); } else if (defaultObject instanceof Integer) { @@ -86,7 +78,6 @@ * 查询某个key是否存在 */ public static boolean containsKey(String key) { - sharedPreferences = context.getSharedPreferences(fileName, Context.MODE_PRIVATE); return sharedPreferences.contains(key); } } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java b/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java deleted file mode 100644 index 0ebf16a..0000000 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/StringHelper.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.casic.birmm.hxrq.utils; - -import android.util.Base64; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; - -/** - * @Author: Pengxh - * @Time: 2021/4/9 15:12 - * @Email: 290677893@qq.com - **/ -public class StringHelper { - /** - * 获取图片base64编码 - */ - public static String imageToBase64(File file) { - if (file == null) { - return null; - } - try { - FileInputStream fis = new FileInputStream(file); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - byte[] b = new byte[1024]; - int n; - while ((n = fis.read(b)) != -1) { - bos.write(b, 0, n); - } - fis.close(); - bos.close(); - - byte[] imgBytes = bos.toByteArray(); - String s = Base64.encodeToString(imgBytes, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING); - return s.replace("-", "+") - .replace("_", "/"); - } catch (Exception e) { - return null; - } - } -} diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java index 8fe5264..1de1ff4 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitService.java @@ -1,6 +1,6 @@ package com.casic.birmm.hxrq.utils.retrofit; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -49,6 +49,6 @@ */ @Headers({"Content-Type: application/json"}) @POST("/cockpit/face/login") - Observable getFaceLoginResult( + Observable getFaceLoginResult( @Body ImageBean imageBean); } diff --git a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java index ef4307e..d481055 100644 --- a/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java +++ b/app/src/main/java/com/casic/birmm/hxrq/utils/retrofit/RetrofitServiceManager.java @@ -2,7 +2,7 @@ import android.util.Log; -import com.casic.birmm.hxrq.bean.FaceLoginResultBean; +import com.casic.birmm.hxrq.bean.FaceResultBean; import com.casic.birmm.hxrq.bean.ImageBean; import com.casic.birmm.hxrq.bean.LoginResultBean; import com.casic.birmm.hxrq.bean.PublicKeyBean; @@ -10,7 +10,6 @@ import com.casic.birmm.hxrq.utils.HttpConfig; import org.jetbrains.annotations.NotNull; -import org.json.JSONObject; import java.util.concurrent.TimeUnit; @@ -79,7 +78,7 @@ /** * 人脸识别登录结果 */ - public static Observable getFaceResult(String baseUrl, ImageBean imageBean) { + public static Observable getFaceResult(String baseUrl, ImageBean imageBean) { Retrofit retrofit = createRetrofit(baseUrl); RetrofitService service = retrofit.create(RetrofitService.class); return service.getFaceLoginResult(imageBean); diff --git a/app/src/main/res/drawable/bg_circle_image.xml b/app/src/main/res/drawable/bg_circle_image.xml new file mode 100644 index 0000000..5b27ca4 --- /dev/null +++ b/app/src/main/res/drawable/bg_circle_image.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_face.xml b/app/src/main/res/layout/activity_face.xml new file mode 100644 index 0000000..0d2e4e0 --- /dev/null +++ b/app/src/main/res/layout/activity_face.xml @@ -0,0 +1,25 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index b300663..5e16fcb 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -74,8 +74,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/loginButton" - android:layout_marginTop="20dp" android:gravity="center" + android:paddingVertical="20dp" android:text="换个方式登录" android:textColor="@color/mainThemeColor" android:textSize="@dimen/textFontSize" /> diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 8da4e0c..00a79de 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,6 +1,5 @@ - +