Compare commits

..
5 Commits
Author SHA1 Message Date
lijia 4d0c8d406a 删除 2023-09-11 15:53:39 +08:00
lijia 68d411e544 Merge branch 'master' into ocrcamera 2023-09-11 15:32:25 +08:00
lijia 44809df2cf 奔溃问题处理 2023-08-31 16:42:24 +08:00
lijia ce9a03b4d6 百度ocr识别依赖添加 2023-08-30 16:10:33 +08:00
lijia 3505a9caa1 ocr测试 2023-08-30 15:56:18 +08:00
87 changed files with 5087 additions and 1263 deletions
+5 -4
View File
@@ -37,8 +37,8 @@ android {
applicationId "com.arpa.hndahesudintocctmsdriver" applicationId "com.arpa.hndahesudintocctmsdriver"
minSdkVersion 23 minSdkVersion 23
targetSdkVersion 30 targetSdkVersion 30
versionCode 59 versionCode 57
versionName "3.2.9" versionName "3.2.7"
flavorDimensions "CHANNEL_VALUE" flavorDimensions "CHANNEL_VALUE"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
javaCompileOptions { javaCompileOptions {
@@ -176,8 +176,8 @@ dependencies {
implementation 'com.scwang.smart:refresh-footer-ball:2.0.1' //球脉冲加载 implementation 'com.scwang.smart:refresh-footer-ball:2.0.1' //球脉冲加载
implementation 'com.scwang.smart:refresh-footer-classics:2.0.1' //经典加载 implementation 'com.scwang.smart:refresh-footer-classics:2.0.1' //经典加载
//更新版本 //更新版本
implementation 'com.github.jenly1314.AppUpdater:app-updater:1.2.0' implementation 'com.github.jenly1314.AppUpdater:app-updater:1.1.0'
implementation 'com.github.jenly1314.AppUpdater:app-dialog:1.2.0' implementation 'com.github.jenly1314.AppUpdater:app-dialog:1.1.0'
//轮播插件 //轮播插件
implementation 'com.github.zhpanvip:BannerViewPager:3.5.4' implementation 'com.github.zhpanvip:BannerViewPager:3.5.4'
// //
@@ -233,5 +233,6 @@ dependencies {
implementation 'com.github.getActivity:XToast:8.2' implementation 'com.github.getActivity:XToast:8.2'
implementation project(path: ':mylibrary') implementation project(path: ':mylibrary')
implementation project(path: ':ocr_ui')
} }
+1 -16
View File
@@ -44,7 +44,7 @@
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.EACCES" /> <uses-permission android:name="android.permission.EACCES" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-feature <uses-feature
android:name="android.hardware.nfc" android:name="android.hardware.nfc"
android:required="true" /> android:required="true" />
@@ -111,21 +111,6 @@
</activity> </activity>
<activity
android:name="com.arpa.hndahesudintocctmsdriver.ui.home.shangchuan.ShangChuangImgActivityBC"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
</activity>
<activity <activity
android:name="com.arpa.hndahesudintocctmsdriver.ui.home.shangchuan.ShangChuangImgActivity2" android:name="com.arpa.hndahesudintocctmsdriver.ui.home.shangchuan.ShangChuangImgActivity2"
android:screenOrientation="portrait"> android:screenOrientation="portrait">
@@ -9,41 +9,27 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Environment;
import android.util.Log; import android.util.Log;
import androidx.core.app.ActivityCompat;
import com.alct.mdp.MDPLocationCollectionManager; import com.alct.mdp.MDPLocationCollectionManager;
import com.arpa.hndahesudintocctmsdriver.report.JTTProcess; import com.arpa.hndahesudintocctmsdriver.report.JTTProcess;
import com.arpa.hndahesudintocctmsdriver.request.net.Api; import com.arpa.hndahesudintocctmsdriver.request.net.Api;
import com.arpa.hndahesudintocctmsdriver.ui.MainActivity; import com.arpa.hndahesudintocctmsdriver.ui.MainActivity;
import com.arpa.hndahesudintocctmsdriver.util.BillLocationUtils; import com.arpa.hndahesudintocctmsdriver.util.BillLocationUtils;
import com.arpa.hndahesudintocctmsdriver.util.SPUtils;
import com.arpa.hndahesudintocctmsdriver.util.location.LocationGDUtil;
import com.dahe.mylibrary.CommonBaseLibrary; import com.dahe.mylibrary.CommonBaseLibrary;
import com.dahe.mylibrary.utils.TimeUtil;
import com.dahe.mylibrary.utils.ToastUtils; import com.dahe.mylibrary.utils.ToastUtils;
import com.esign.esignsdk.EsignSdk; import com.esign.esignsdk.EsignSdk;
import com.arpa.hndahesudintocctmsdriver.util.sp.SPUtil; import com.arpa.hndahesudintocctmsdriver.util.sp.SPUtil;
import com.gyf.cactus.Cactus; import com.gyf.cactus.Cactus;
import com.gyf.cactus.callback.CactusBackgroundCallback; import com.gyf.cactus.callback.CactusBackgroundCallback;
import com.gyf.cactus.callback.CactusCallback; import com.gyf.cactus.callback.CactusCallback;
import com.permissionx.guolindev.PermissionX;
import com.tencent.bugly.crashreport.CrashReport;
import com.umeng.commonsdk.UMConfigure; import com.umeng.commonsdk.UMConfigure;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import cn.jiguang.verifysdk.api.JVerificationInterface; import cn.jiguang.verifysdk.api.JVerificationInterface;
public class App extends Application implements CactusCallback { public class App extends Application {
// String key = "f9d35b1133cff1f6e3960c89b249e03f"; // String key = "f9d35b1133cff1f6e3960c89b249e03f";
String key = "19ac0aa74338e487e45057faf7212401"; String key = "19ac0aa74338e487e45057faf7212401";
String license = "HF41uGxM/1i3CtW98DimoA97BlNTAnQ+DiEAihYmZ2jR1jqC4be253joEJbOJgFDIzp5aIoeuXSWWHFaDVfaHL2Pksbq5f8M8EqsVhP9q/i1xGYSYf6MJVlHdMAVLWgR0Kra+n8dVzkSDuZeyJuDsskAmZaGFQN1CqnWYCI1tmV1Tk4A57e9LQMed0U11QWjdshdU2DGqBXKmGE419PdW3NmIxOR2u9iB1OKBmvzCUT8RAYyBzSn/yhU++YJ25g5a8Pb5kOvi+eOh+PEFEcQL6oOp/CF4Iw5nadlsLhc+XEnVJpwL2myZBoSlVcKxrJKbRn1/DIgXBueKKnqhyHKdJlpqI9eghAlRF0p2Q4f23m89mWRZf4nhKzTeXGIjCTFO4TNVucrlGU7tyJcrRCDVdfV24fziH+hB3QGckpuYzzjefr7hZalLRJ/w8dPw/8dCY1wnWq3AJ3zw2g1PzMxl51q7AgdKvwc1ERcGBns0zb8PK6vGKCnJq3uHiJEnslbTI0MEosje+h+OPO7hf2QofErewjI19wHEOv4dTvuFLh3VmGFMObAmov5kI47705fjSxCvAPGATBrfUSwim+5EQ1hanc5IcXe0/nOTiRUNEpZ+x65zVydqAs7490yqQiIUQvPazEwcal7vH2OD54lCcgpxKxqdmGc5/bp5UnqB45+n+iuInV/Q9DMOQVk15uaVZmhS8VaCqH21CmfH/ZGLb9wiEpaRLrPZLKX3bK7MT9Z0/OlDnb2QUKU8LMMIhLuQQntzsf0Wn4kA/0e9QAJJQ=="; String license = "HF41uGxM/1i3CtW98DimoA97BlNTAnQ+DiEAihYmZ2jR1jqC4be253joEJbOJgFDIzp5aIoeuXSWWHFaDVfaHL2Pksbq5f8M8EqsVhP9q/i1xGYSYf6MJVlHdMAVLWgR0Kra+n8dVzkSDuZeyJuDsskAmZaGFQN1CqnWYCI1tmV1Tk4A57e9LQMed0U11QWjdshdU2DGqBXKmGE419PdW3NmIxOR2u9iB1OKBmvzCUT8RAYyBzSn/yhU++YJ25g5a8Pb5kOvi+eOh+PEFEcQL6oOp/CF4Iw5nadlsLhc+XEnVJpwL2myZBoSlVcKxrJKbRn1/DIgXBueKKnqhyHKdJlpqI9eghAlRF0p2Q4f23m89mWRZf4nhKzTeXGIjCTFO4TNVucrlGU7tyJcrRCDVdfV24fziH+hB3QGckpuYzzjefr7hZalLRJ/w8dPw/8dCY1wnWq3AJ3zw2g1PzMxl51q7AgdKvwc1ERcGBns0zb8PK6vGKCnJq3uHiJEnslbTI0MEosje+h+OPO7hf2QofErewjI19wHEOv4dTvuFLh3VmGFMObAmov5kI47705fjSxCvAPGATBrfUSwim+5EQ1hanc5IcXe0/nOTiRUNEpZ+x65zVydqAs7490yqQiIUQvPazEwcal7vH2OD54lCcgpxKxqdmGc5/bp5UnqB45+n+iuInV/Q9DMOQVk15uaVZmhS8VaCqH21CmfH/ZGLb9wiEpaRLrPZLKX3bK7MT9Z0/OlDnb2QUKU8LMMIhLuQQntzsf0Wn4kA/0e9QAJJQ==";
@@ -54,14 +40,12 @@ public class App extends Application implements CactusCallback {
public static int APP_STATUS = APP_STATUS_KILLED; // 记录App的启动状态 public static int APP_STATUS = APP_STATUS_KILLED; // 记录App的启动状态
private Context con; private Context con;
public static App mApplication = null; public static App mApplication = null;
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
mApplication = this; mApplication = this;
con = getBaseContext(); con = getBaseContext();
CommonBaseLibrary.getInstance().init(this, Api.BASE_URL); CommonBaseLibrary.getInstance().init(this, Api.BASE_URL);
CrashReport.initCrashReport(getApplicationContext(), "0fa55ffad8", false);
String state = SPUtil.getSP(con, "state_data", "authorization_state"); String state = SPUtil.getSP(con, "state_data", "authorization_state");
if ("1".equals(state)) { if ("1".equals(state)) {
try { try {
@@ -92,34 +76,29 @@ public class App extends Application implements CactusCallback {
} }
} }
PendingIntent pendingIntent = // PendingIntent pendingIntent =
PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT); // PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT);
Cactus.getInstance() // Cactus.getInstance()
.isDebug(true) // .isDebug(true)
.setTitle("好运司机") // //可选,设置通知栏点击事件
.setContent("您的接单助手!") // .setPendingIntent(pendingIntent)
.setChannelId("gld") //// .setBackgroundMusicEnabled(true)//可选,退到后台是否可以播放音乐
.setChannelName("好运司机") //// .setMusicId(R.raw.main) //可选,设置音乐
.setServiceId(Integer.MAX_VALUE) //// .setPendingIntent(pendingIntent)//可选,设置通知栏点击事件
//可选,设置通知栏点击事件 //// .addCallback(new CactusCallback())//可选,运行时回调
.setPendingIntent(pendingIntent) // .setCrashRestartUIEnabled(true) //可选,设置奔溃可以重启,google原生rom android 10以下可以正常重启
.setBackgroundMusicEnabled(true)//可选,退到后台是否可以播放音乐 // .setCrashRestartUIEnabled(true)//可选,设置奔溃可以重启,google原生rom android 10以下可以正常重启
.setMusicId(R.raw.main) //可选,设置音乐 // .setTitle("大河好运")
// .setPendingIntent(pendingIntent)//可选,设置通知栏点击事件 // .setSmallIcon(R.drawable.diver_logo)
// .addCallback(new CactusCallback())//可选,运行时回调 // .addBackgroundCallback(new CactusBackgroundCallback() {
.setCrashRestartUIEnabled(true) //可选,设置奔溃可以重启,google原生rom android 10以下可以正常重启 // @Override
.setCrashRestartUIEnabled(true)//可选,设置奔溃可以重启,google原生rom android 10以下可以正常重启 // public void onBackground(boolean b) {
.setSmallIcon(R.drawable.diver_logo) // if (b){
.addCallback(this) // getBillLocation();
.addBackgroundCallback(new CactusBackgroundCallback() { // }
@Override // }
public void onBackground(boolean b) { // })
if (b) { // .register(this);
getBillLocation();
}
}
})
.register(this);
} }
public static App getApp() { public static App getApp() {
@@ -168,62 +147,4 @@ public class App extends Application implements CactusCallback {
return false; return false;
} }
@Override
public void doWork(int i) {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
FileOutputStream fos = null;
try {
String nowString = TimeUtil.getNowString(TimeUtil.DEFAULT_FORMAT);
String content = i + "当前时间:"+nowString;
String fileName = "location" + ".txt";
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
//获取文件输出路径
String path = Environment.getExternalStorageDirectory()
+ "/crashinfo2/";
//创建文件夹和文件
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
// File file = new File(path + fileName);
// if (!file.exists())
// file.createNewFile();
//创建输出流
fos = new FileOutputStream(path + fileName,true);
File file = new File(path + fileName);
if (file.exists()){
fos.write('\r');
}
//向文件中写出数据
fos.write(content.toString().getBytes());
}
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (fos != null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}, 100, 1000);
}
@Override
public void onStop() {
}
} }
@@ -224,6 +224,27 @@ public class H5Activity extends AppCompatActivity {
Uri uri = Uri.parse(url); Uri uri = Uri.parse(url);
Log.e("test", "要加载的地址:" + uri.getScheme() + " " + url + " "); Log.e("test", "要加载的地址:" + uri.getScheme() + " " + url + " ");
// if (url.contains("callback")) {
// // 实名认证结束 返回按钮/倒计时返回/暂不认证
// boolean status = uri.getBooleanQueryParameter("passed", false);
// if (status) {
//
// new Handler().postDelayed(() -> {
// FaceEvent he = new FaceEvent("刷脸成功");
// EventBus.getDefault().post(he);
// finish();
// }, 4000);
// }else{
// if (mWebView.canGoBack()) {
// mWebView.goBack();
// }
// Toast.makeText(H5Activity.this, "认证失败,请重新刷脸认证", Toast.LENGTH_SHORT).show();
// }
// return true;
// }
if (uri.getScheme().equals("http") || uri.getScheme().equals("https")) { if (uri.getScheme().equals("http") || uri.getScheme().equals("https")) {
view.loadUrl(url); view.loadUrl(url);
return true; return true;
@@ -1,18 +1,11 @@
package com.arpa.hndahesudintocctmsdriver.cuspop package com.arpa.hndahesudintocctmsdriver.cuspop
import android.Manifest
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.view.View import android.view.View
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import com.arpa.hndahesudintocctmsdriver.R import com.arpa.hndahesudintocctmsdriver.R
import com.arpa.hndahesudintocctmsdriver.util.alert.ToastUtil
import com.dahe.mylibrary.utils.ToastUtils
import com.lxj.xpopup.core.CenterPopupView import com.lxj.xpopup.core.CenterPopupView
import com.lxj.xpopup.util.XPermission
import com.permissionx.guolindev.PermissionX
import kotlinx.android.synthetic.main.load.view.* import kotlinx.android.synthetic.main.load.view.*
import kotlinx.android.synthetic.main.pop_message_center.view.* import kotlinx.android.synthetic.main.pop_message_center.view.*
@@ -55,16 +48,11 @@ class MessagePop(context: Context) : CenterPopupView(context), View.OnClickListe
} }
R.id.tvOk,R.id.tvPhone -> { R.id.tvOk,R.id.tvPhone -> {
dismiss() dismiss()
if (XPermission.create(context).isGranted(Manifest.permission.CALL_PHONE)){ val toString = tvPhone.text.toString()
val toString = tvPhone.text.toString() val intent = Intent(Intent.ACTION_DIAL)
val intent = Intent(Intent.ACTION_DIAL) val data = Uri.parse("tel:$toString")
val data = Uri.parse("tel:$toString") intent.data = data
intent.data = data context.startActivity(intent)
context.startActivity(intent)
}else{
ToastUtils.showToast(context,"请开启电话权限")
}
// BaseUtils.callPhone(content as Activity, tvPhone.text.toString()) // BaseUtils.callPhone(content as Activity, tvPhone.text.toString())
} }
} }
@@ -138,7 +138,6 @@ class MainActivity : BaseAppCompatActivity() {
Manifest.permission.ACCESS_BACKGROUND_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CALL_PHONE,
Manifest.permission.RECORD_AUDIO, Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA) Manifest.permission.CAMERA)
.request { allGranted, grantedList, deniedList -> .request { allGranted, grantedList, deniedList ->
@@ -2,7 +2,6 @@ package com.arpa.hndahesudintocctmsdriver.ui.alert;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
@@ -13,8 +12,6 @@ import androidx.annotation.NonNull;
import com.king.app.updater.AppUpdater; import com.king.app.updater.AppUpdater;
import com.king.app.updater.callback.AppUpdateCallback; import com.king.app.updater.callback.AppUpdateCallback;
import com.king.app.updater.constant.Constants;
import com.king.app.updater.util.AppUtils;
import com.lxj.xpopup.core.CenterPopupView; import com.lxj.xpopup.core.CenterPopupView;
import com.arpa.hndahesudintocctmsdriver.R; import com.arpa.hndahesudintocctmsdriver.R;
@@ -30,8 +27,8 @@ import java.io.File;
*/ */
public class UpAppAlert extends CenterPopupView { public class UpAppAlert extends CenterPopupView {
private TextView content,vs,tvContent; private TextView content,vs;
private Button tv_cancel,tv_confirm,tvOk; private Button tv_cancel,tv_confirm;
private LinearLayout up_div; private LinearLayout up_div;
private String url=""; private String url="";
private String body=""; private String body="";
@@ -66,8 +63,6 @@ public class UpAppAlert extends CenterPopupView {
content=findViewById(R.id.tv_content); content=findViewById(R.id.tv_content);
tv_cancel=findViewById(R.id.tv_cancel); tv_cancel=findViewById(R.id.tv_cancel);
tv_confirm=findViewById(R.id.tv_confirm); tv_confirm=findViewById(R.id.tv_confirm);
tvContent=findViewById(R.id.tvContent);
tvOk=findViewById(R.id.tvOk);
up_div=findViewById(R.id.up_div); up_div=findViewById(R.id.up_div);
progress_view=findViewById(R.id.progress); progress_view=findViewById(R.id.progress);
content=findViewById(R.id.tv_content); content=findViewById(R.id.tv_content);
@@ -114,11 +109,7 @@ public class UpAppAlert extends CenterPopupView {
@Override @Override
public void onFinish(File file) { public void onFinish(File file) {
tvContent.setText("下载完成,请及时安装!");
tvOk.setVisibility(VISIBLE);
tvOk.setOnClickListener(v1 -> {
AppUtils.installApk(getContext(),file,getContext().getPackageName() + Constants.DEFAULT_FILE_PROVIDER);
});
} }
}) })
.start(); .start();
@@ -229,11 +229,6 @@ public class AuthQualificationActivity extends BaseAppCompatActivity {
gia.showPopueWindow(this); gia.showPopueWindow(this);
} }
}); });
up_img.setOnClickListener(v -> {
if (!isAuth) {
gia.showPopueWindow(this);
}
});
img.setOnClickListener(v -> { img.setOnClickListener(v -> {
if (!"".equals(url)) { if (!"".equals(url)) {
new XPopup.Builder(con).asImageViewer(img, url, new SmartGlideImageLoader(R.mipmap.ic_launcher_round)).show(); new XPopup.Builder(con).asImageViewer(img, url, new SmartGlideImageLoader(R.mipmap.ic_launcher_round)).show();
@@ -255,7 +250,7 @@ public class AuthQualificationActivity extends BaseAppCompatActivity {
String id = value1.getText() + ""; String id = value1.getText() + "";
String date = value2.getText() + ""; String date = value2.getText() + "";
if ("0".equals(type)) { if ("0".equals(type)) {
if (!"".equals(date) && !"".equals(url)) { if (!"".equals(id) && !"".equals(date) && !"".equals(url)) {
new AuthRequest().driverAuthQualification(con, hd, id, ub.getData().getId(), date); new AuthRequest().driverAuthQualification(con, hd, id, ub.getData().getId(), date);
} else { } else {
Toast.makeText(con, "请补充证件信息", Toast.LENGTH_SHORT).show(); Toast.makeText(con, "请补充证件信息", Toast.LENGTH_SHORT).show();
@@ -315,10 +315,6 @@ public class PhotoCarActivity extends BaseAppCompatActivity implements View.OnCl
* 展示大图片 * 展示大图片
*/ */
private void showBigImg() { private void showBigImg() {
if (TextUtils.isEmpty(cdb.getData().getRoadLicensePhoto())){
choicePhoto();
return;
}
switch (type) { switch (type) {
case 0: case 0:
if (cdb.getData().getRoadLicensePhoto() != null && !cdb.getData().getCarImage().equals("")) { if (cdb.getData().getRoadLicensePhoto() != null && !cdb.getData().getCarImage().equals("")) {
@@ -47,6 +47,7 @@ import com.arpa.hndahesudintocctmsdriver.ui.auth.CertificatesActivity;
import com.arpa.hndahesudintocctmsdriver.ui.news.NewActivity; import com.arpa.hndahesudintocctmsdriver.ui.news.NewActivity;
import com.arpa.hndahesudintocctmsdriver.util.MessageUtils; import com.arpa.hndahesudintocctmsdriver.util.MessageUtils;
import com.arpa.hndahesudintocctmsdriver.util.string.StringUtil; import com.arpa.hndahesudintocctmsdriver.util.string.StringUtil;
import com.baidu.ocr.ui.camera.CameraActivity;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.gyf.cactus.Cactus; import com.gyf.cactus.Cactus;
@@ -94,6 +95,7 @@ import com.youth.banner.loader.ImageLoader;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.Subscribe;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -336,13 +338,20 @@ public class HomeFragment extends BaseFragment {
} }
}); });
news_btn.setOnClickListener(v -> { news_btn.setOnClickListener(v -> {
if (UiAuxiliary.isLogin(con)) { // TODO: 2023/8/30 测试orc拍照
Intent in = new Intent(con, NewActivity.class); Intent intent = new Intent(getActivity(), CameraActivity.class);
startActivity(in); intent.putExtra(CameraActivity.KEY_OUTPUT_FILE_PATH,
} else { new File(getActivity().getFilesDir(), "pic.jpg").getAbsolutePath());
Intent in = new Intent(con, LoginActivity.class); intent.putExtra(CameraActivity.KEY_CONTENT_TYPE, CameraActivity.CONTENT_TYPE_ID_CARD_FRONT);
startActivity(in); startActivityForResult(intent, 1111);
}
// if (UiAuxiliary.isLogin(con)) {
// Intent in = new Intent(con, NewActivity.class);
// startActivity(in);
// } else {
// Intent in = new Intent(con, LoginActivity.class);
// startActivity(in);
// }
}); });
//Intent serviceIn=new Intent(con, LocationService.class); //Intent serviceIn=new Intent(con, LocationService.class);
//getActivity().startService(serviceIn); //getActivity().startService(serviceIn);
@@ -387,21 +387,21 @@ public class StartYunDanActivity extends BaseActivity {
for (int i = 0; i < sob.getData().getWayChildren().size(); i++) { for (int i = 0; i < sob.getData().getWayChildren().size(); i++) {
if (sob.getData().getWayChildren().get(i).getType() == 1) { if (sob.getData().getWayChildren().get(i).getType() == 1) {
zInfo = sob.getData().getWayChildren().get(i); zInfo = sob.getData().getWayChildren().get(i);
if (zInfo.getReceiptUrl() != null && zInfo.getReceiptUrl().size() > 0) { int dis = TimeUtil.compareNowDate(TimeUtil.string2Millis(zInfo.getImageTakenDate(), TimeUtil.DEFAULT_FORMAT4));
int dis = TimeUtil.compareNowDate(TimeUtil.string2Millis(zInfo.getImageTakenDate(), TimeUtil.DEFAULT_FORMAT4)); if (dis > 5) {
if (dis > 5) {//大于五分钟可以接单 if (zInfo.getReceiptUrl() != null && zInfo.getReceiptUrl().size() > 0) {
Intent in = new Intent(con, ShangChuangImgActivity.class); Intent in = new Intent(con, ShangChuangImgActivity.class);
in.putExtra("type", type); in.putExtra("type", type);
in.putExtra("wid", wid); in.putExtra("wid", wid);
in.putExtra("sob", gson.toJson(sob)); in.putExtra("sob", gson.toJson(sob));
in.putExtra("keys", key); in.putExtra("keys", key);
startActivity(in); startActivity(in);
break;
} else { } else {
ToastUtils.showToast(StartYunDanActivity.this, "到卸货地再进行卸货操作!"); ToastUtils.showToast(StartYunDanActivity.this, "先上传出货单,再进行卸货操作!");
} }
break; } else {//大于五分钟可以接单
} else { ToastUtils.showToast(StartYunDanActivity.this, "装卸货时间间隔过短,请稍后重试!");
ToastUtils.showToast(StartYunDanActivity.this, "请先上传出货单,再进行卸货操作!");
} }
break; break;
} }
@@ -29,9 +29,12 @@ import com.arpa.hndahesudintocctmsdriver.util.NfcUtils;
import com.arpa.hndahesudintocctmsdriver.util.alert.ToastUtil; import com.arpa.hndahesudintocctmsdriver.util.alert.ToastUtil;
import com.arpa.hndahesudintocctmsdriver.util.img.GetCarImageAlert; import com.arpa.hndahesudintocctmsdriver.util.img.GetCarImageAlert;
import com.arpa.hndahesudintocctmsdriver.util.location.LocationUtil; import com.arpa.hndahesudintocctmsdriver.util.location.LocationUtil;
import com.baidu.mapapi.CoordType;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.model.LatLng; import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.utils.CoordinateConverter; import com.baidu.mapapi.utils.CoordinateConverter;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.dahe.mylibrary.utils.ToastUtils;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.luck.picture.lib.PictureSelector; import com.luck.picture.lib.PictureSelector;
import com.luck.picture.lib.config.PictureConfig; import com.luck.picture.lib.config.PictureConfig;
@@ -44,6 +47,7 @@ import com.arpa.hndahesudintocctmsdriver.bean.UploadBean;
import com.arpa.hndahesudintocctmsdriver.request.HuoYuanRequset; import com.arpa.hndahesudintocctmsdriver.request.HuoYuanRequset;
import com.arpa.hndahesudintocctmsdriver.request.bean.LUInputBean; import com.arpa.hndahesudintocctmsdriver.request.bean.LUInputBean;
import com.arpa.hndahesudintocctmsdriver.request.bean.UploadReceiptInputBean; import com.arpa.hndahesudintocctmsdriver.request.bean.UploadReceiptInputBean;
import com.arpa.hndahesudintocctmsdriver.ui.auth.CertificatesActivity;
import com.arpa.hndahesudintocctmsdriver.util.location.LocationGDUtil; import com.arpa.hndahesudintocctmsdriver.util.location.LocationGDUtil;
import com.arpa.hndahesudintocctmsdriver.util.alert.CustomDialog; import com.arpa.hndahesudintocctmsdriver.util.alert.CustomDialog;
import com.arpa.hndahesudintocctmsdriver.util.cache.CacheGroup; import com.arpa.hndahesudintocctmsdriver.util.cache.CacheGroup;
@@ -111,17 +115,17 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
if (CacheGroup.cacheList.get(TYPE_NAME[i]) != null) { if (CacheGroup.cacheList.get(TYPE_NAME[i]) != null) {
BaseBean bb = gson.fromJson(CacheGroup.cacheList.get(TYPE_NAME[i]), BaseBean.class); BaseBean bb = gson.fromJson(CacheGroup.cacheList.get(TYPE_NAME[i]), BaseBean.class);
if (bb.getCode() == 200) { if (bb.getCode() == 200) {
if (index == 2) { if (!keys) {
if (!keys){//装货回单 Toast.makeText(con, "上传成功", Toast.LENGTH_SHORT).show();
Toast.makeText(con, "上传成功", Toast.LENGTH_SHORT).show(); finish();
finish(); } else {
} Toast.makeText(con, "上传成功", Toast.LENGTH_SHORT).show();
finish();
} }
} else { } else {
Toast.makeText(con, bb.getMsg(), Toast.LENGTH_SHORT).show(); Toast.makeText(con, bb.getMsg(), Toast.LENGTH_SHORT).show();
} }
CacheGroup.cacheList.remove(TYPE_NAME[i]); CacheGroup.cacheList.remove(TYPE_NAME[i]);
break;
} }
} }
if (CacheGroup.cacheList.get("carName") != null) { if (CacheGroup.cacheList.get("carName") != null) {
@@ -163,7 +167,6 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
customDialog.dismiss(); customDialog.dismiss();
tv_loaction.setText("定位成功"); tv_loaction.setText("定位成功");
tv_loaction.setTextColor(getResources().getColor(R.color.theme_color, null)); tv_loaction.setTextColor(getResources().getColor(R.color.theme_color, null));
latLng = convertGPSToBaidu(new LatLng(lgdu.getLatitude(), lgdu.getLongitude()));
initLocation(); initLocation();
break; break;
case 16://定位失败 case 16://定位失败
@@ -196,14 +199,6 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
break; break;
} }
} }
private LatLng latLng;
public LatLng convertGPSToBaidu(LatLng srLatLng) {
CoordinateConverter converter = new CoordinateConverter();
converter.from(CoordinateConverter.CoordType.COMMON);
converter.coord(srLatLng);
return converter.convert();
}
private String wid; private String wid;
private int h_type; private int h_type;
@@ -240,8 +235,8 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
lgdu = new LocationGDUtil(con, hd); lgdu = new LocationGDUtil(con, hd);
//启动定位 //启动定位
lgdu.onCreate(); lgdu.onCreate();
// lu = new LocationUtil(con, hd); lu = new LocationUtil(con, hd);
// lu.onCreate(); lu.onCreate();
// if (keys) { // if (keys) {
// lu = new LocationUtil(con, hd); // lu = new LocationUtil(con, hd);
// lu.onCreate(); // lu.onCreate();
@@ -250,8 +245,8 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
if (!locationKey) { if (!locationKey) {
customDialog.show(); customDialog.show();
lgdu.onCreate(); lgdu.onCreate();
// lu = new LocationUtil(con, hd); lu = new LocationUtil(con, hd);
// lu.onCreate(); lu.onCreate();
} }
}); });
hyr = new HuoYuanRequset(con, hd); hyr = new HuoYuanRequset(con, hd);
@@ -361,6 +356,10 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
Log.e("--装货信息", gson.toJson(lub)); Log.e("--装货信息", gson.toJson(lub));
if (locationKey) {//高德定位 if (locationKey) {//高德定位
if (keys) { if (keys) {
if (lu!=null&&lu.getErrorCode()!=161){
ToastUtils.showToast(this,"百度地图定位失败,请确认开启定位后重试!");
return;
}
nfc(); nfc();
loadInfo(); loadInfo();
// up_traffic_start(); // up_traffic_start();
@@ -385,6 +384,10 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
Log.e("--卸货信息", gson.toJson(lub)); Log.e("--卸货信息", gson.toJson(lub));
if (locationKey) { if (locationKey) {
if (keys) { if (keys) {
if (lu!=null&&lu.getErrorCode()!=161){
ToastUtils.showToast(this,"百度地图定位失败,请确认开启定位后重试!");
return;
}
nfc(); nfc();
uploadInfo(); uploadInfo();
@@ -413,6 +416,10 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
Log.e("--回单信息", gson.toJson(urib)); Log.e("--回单信息", gson.toJson(urib));
if (locationKey) { if (locationKey) {
if (index == 2 && keys) { if (index == 2 && keys) {
if (lu!=null&&lu.getErrorCode()!=161){
ToastUtils.showToast(this,"百度地图定位失败,请确认开启定位后重试!");
return;
}
up_trafficSign(); up_trafficSign();
up_trafficReceipt(); up_trafficReceipt();
receipt_image(); receipt_image();
@@ -432,6 +439,34 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
private StartOrderBean sob; private StartOrderBean sob;
//上传安联和交通厅-装货
public void up_traffic_start() {
//安联
if (sob.getData().getReportAlct() == 1) {
Location l = new Location();
l.setBaiduLongitude(lu.getLongitude());
l.setBaiduLatitude(lu.getLatitude());
l.setLocation(lu.getAddress());
l.setTime(Timer.getTimerT());
MDPLocationCollectionManager.pickup(con, sob.getData().getShippingNoteNumber(), l, new com.alct.mdp.callback.OnResultListener() {
@Override
public void onSuccess() {
Log.e("上报安联", "装货上传成功");
}
@Override
public void onFailure(String s, String s1) {
Log.e("上报安联失败(装货):", s + s1);
new MessageUtils().showCenMessage(con, s1);
}
});
}
//交通厅
if (sob.getData().getReport() == 1) {
JTTProcess.start(con, sob, "");
}
}
public void nfc() { public void nfc() {
// if(sob.getData().getNfcId().equals(nfcStr)){ // if(sob.getData().getNfcId().equals(nfcStr)){
// Toast.makeText(con,"nfcId匹配失败",Toast.LENGTH_LONG).show(); // Toast.makeText(con,"nfcId匹配失败",Toast.LENGTH_LONG).show();
@@ -453,13 +488,41 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
}); });
} }
//上传安联和交通厅-卸货
public void up_traffic_end() {
//安联
if (sob.getData().getReportAlct() == 1) {
Location l = new Location();
l.setBaiduLongitude(lu.getLongitude());
l.setBaiduLatitude(lu.getLatitude());
l.setLocation(lu.getAddress());
l.setTime(Timer.getTimerT());
Log.e("-安联卸货信息-", gson.toJson(l));
MDPLocationCollectionManager.unload(con, sob.getData().getShippingNoteNumber(), l, new com.alct.mdp.callback.OnResultListener() {
@Override
public void onSuccess() {
Log.e("上报安联", "卸货上传成功");
}
@Override
public void onFailure(String s, String s1) {
Log.e("上报安联失败(卸货):", s + s1);
}
});
}
//交通厅
if (sob.getData().getReport() == 1) {
JTTProcess.stop(con, sob, "");
}
}
//上传安联-签收 //上传安联-签收
public void up_trafficSign() { public void up_trafficSign() {
//安联 //安联
Location l = new Location(); Location l = new Location();
l.setBaiduLongitude(latLng.longitude); l.setBaiduLongitude(lu.getLongitude());
l.setBaiduLatitude(latLng.latitude); l.setBaiduLatitude(lu.getLatitude());
l.setLocation(lgdu.getAddress()); l.setLocation(lu.getAddress());
l.setTime(Timer.getTimerT()); l.setTime(Timer.getTimerT());
List<Goods> gs = new ArrayList<>(); List<Goods> gs = new ArrayList<>();
for (StartOrderBean.DataDTO.WayChildrenDTO wayChild : sob.getData().getWayChildren()) { for (StartOrderBean.DataDTO.WayChildrenDTO wayChild : sob.getData().getWayChildren()) {
@@ -497,9 +560,9 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
public void up_trafficReceipt() { public void up_trafficReceipt() {
//安联 //安联
Location l = new Location(); Location l = new Location();
l.setBaiduLongitude(latLng.longitude); l.setBaiduLongitude(lu.getLongitude());
l.setBaiduLatitude(latLng.latitude); l.setBaiduLatitude(lu.getLatitude());
l.setLocation(lgdu.getAddress()); l.setLocation(lu.getAddress());
l.setTime(Timer.getTimerT()); l.setTime(Timer.getTimerT());
MDPLocationCollectionManager.pod(con, sob.getData().getShippingNoteNumber(), l, new com.alct.mdp.callback.OnResultListener() { MDPLocationCollectionManager.pod(con, sob.getData().getShippingNoteNumber(), l, new com.alct.mdp.callback.OnResultListener() {
@@ -525,16 +588,14 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
image.setFileExt(FileUtil.lastName(file)); image.setFileExt(FileUtil.lastName(file));
image.setFileName(FileUtil.fileName(file)); image.setFileName(FileUtil.fileName(file));
image.setImageTakenDate(Timer.getTimerT()); image.setImageTakenDate(Timer.getTimerT());
image.setBaiduLongitude(latLng.longitude); image.setBaiduLongitude(lu.getLongitude());
image.setBaiduLatitude(latLng.latitude); image.setBaiduLatitude(lu.getLatitude());
image.setLocation(lgdu.getAddress()); image.setLocation(lu.getAddress());
MDPLocationCollectionManager.uploadPickupImage(con, sob.getData().getShippingNoteNumber(), image, new com.alct.mdp.callback.OnResultListener() { MDPLocationCollectionManager.uploadPickupImage(con, sob.getData().getShippingNoteNumber(), image, new com.alct.mdp.callback.OnResultListener() {
@Override @Override
public void onSuccess() { public void onSuccess() {
Log.e("上报安联", "装货照片上传成功"); Log.e("上报安联", "装货照片上传成功");
Toast.makeText(con, "上传成功", Toast.LENGTH_SHORT).show();
finish();
} }
@Override @Override
@@ -557,16 +618,14 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
image.setFileExt(FileUtil.lastName(file)); image.setFileExt(FileUtil.lastName(file));
image.setFileName(FileUtil.fileName(file)); image.setFileName(FileUtil.fileName(file));
image.setImageTakenDate(Timer.getTimerT()); image.setImageTakenDate(Timer.getTimerT());
image.setBaiduLongitude(latLng.longitude); image.setBaiduLongitude(lu.getLongitude());
image.setBaiduLatitude(latLng.latitude); image.setBaiduLatitude(lu.getLatitude());
image.setLocation(lgdu.getAddress()); image.setLocation(lu.getAddress());
MDPLocationCollectionManager.uploadUnloadImage(con, sob.getData().getShippingNoteNumber(), image, new com.alct.mdp.callback.OnResultListener() { MDPLocationCollectionManager.uploadUnloadImage(con, sob.getData().getShippingNoteNumber(), image, new com.alct.mdp.callback.OnResultListener() {
@Override @Override
public void onSuccess() { public void onSuccess() {
Log.e("上报安联", "卸货照片上传成功"); Log.e("上报安联", "卸货照片上传成功");
Toast.makeText(con, "上传成功", Toast.LENGTH_SHORT).show();
finish();
} }
@Override @Override
@@ -590,16 +649,14 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
image.setFileExt(FileUtil.lastName(file)); image.setFileExt(FileUtil.lastName(file));
image.setFileName(FileUtil.fileName(file)); image.setFileName(FileUtil.fileName(file));
image.setImageTakenDate(Timer.getTimerT()); image.setImageTakenDate(Timer.getTimerT());
image.setBaiduLongitude(latLng.longitude); image.setBaiduLongitude(lu.getLongitude());
image.setBaiduLatitude(latLng.latitude); image.setBaiduLatitude(lu.getLatitude());
image.setLocation(lgdu.getAddress()); image.setLocation(lu.getAddress());
MDPLocationCollectionManager.uploadPODImage(con, sob.getData().getShippingNoteNumber(), image, new com.alct.mdp.callback.OnResultListener() { MDPLocationCollectionManager.uploadPODImage(con, sob.getData().getShippingNoteNumber(), image, new com.alct.mdp.callback.OnResultListener() {
@Override @Override
public void onSuccess() { public void onSuccess() {
Log.e("上报安联", "回单照片上传成功"); Log.e("上报安联", "回单照片上传成功");
Toast.makeText(con, "上传成功", Toast.LENGTH_SHORT).show();
finish();
} }
@Override @Override
@@ -643,9 +700,6 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
Log.e("nfc", nfcStr); Log.e("nfc", nfcStr);
} }
/** /**
* 上传安联和交通厅,平台-装货 * 上传安联和交通厅,平台-装货
*/ */
@@ -653,9 +707,9 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
//安联 //安联
if (sob.getData().getReportAlct() == 1) { if (sob.getData().getReportAlct() == 1) {
Location l = new Location(); Location l = new Location();
l.setBaiduLongitude(latLng.longitude); l.setBaiduLongitude(lu.getLongitude());
l.setBaiduLatitude(latLng.latitude); l.setBaiduLatitude(lu.getLatitude());
l.setLocation(lgdu.getAddress()); l.setLocation(lu.getAddress());
l.setTime(Timer.getTimerT()); l.setTime(Timer.getTimerT());
MDPLocationCollectionManager.pickup(con, sob.getData().getShippingNoteNumber(), l, new com.alct.mdp.callback.OnResultListener() { MDPLocationCollectionManager.pickup(con, sob.getData().getShippingNoteNumber(), l, new com.alct.mdp.callback.OnResultListener() {
@Override @Override
@@ -665,10 +719,10 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
if (sob.getData().getReport() == 1) { if (sob.getData().getReport() == 1) {
JTTProcess.start(con, sob, ""); JTTProcess.start(con, sob, "");
} }
//装货状态
hyr.loading(lub);
//装货照片 //装货照片
up_image_z(); up_image_z();
//装货状态
hyr.loading(lub);
} }
@Override @Override
@@ -689,9 +743,9 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
//安联 //安联
if (sob.getData().getReportAlct() == 1) { if (sob.getData().getReportAlct() == 1) {
Location l = new Location(); Location l = new Location();
l.setBaiduLongitude(latLng.longitude); l.setBaiduLongitude(lu.getLongitude());
l.setBaiduLatitude(latLng.latitude); l.setBaiduLatitude(lu.getLatitude());
l.setLocation(lgdu.getAddress()); l.setLocation(lu.getAddress());
l.setTime(Timer.getTimerT()); l.setTime(Timer.getTimerT());
Log.e("-安联卸货信息-", gson.toJson(l)); Log.e("-安联卸货信息-", gson.toJson(l));
MDPLocationCollectionManager.unload(con, sob.getData().getShippingNoteNumber(), l, new com.alct.mdp.callback.OnResultListener() { MDPLocationCollectionManager.unload(con, sob.getData().getShippingNoteNumber(), l, new com.alct.mdp.callback.OnResultListener() {
@@ -702,10 +756,10 @@ public class ShangChuangImgActivity extends BaseAppCompatActivity {
if (sob.getData().getReport() == 1) { if (sob.getData().getReport() == 1) {
JTTProcess.stop(con, sob, ""); JTTProcess.stop(con, sob, "");
} }
//卸货状态-平台
hyr.dischargeCargo(lub);
//卸货照片-安联 //卸货照片-安联
up_image(); up_image();
//卸货状态-平台
hyr.dischargeCargo(lub);
} }
@Override @Override
@@ -1,760 +0,0 @@
package com.arpa.hndahesudintocctmsdriver.ui.home.shangchuan;
import android.content.Intent;
import android.os.Bundle;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import com.alct.mdp.MDPLocationCollectionManager;
import com.alct.mdp.callback.OnResultListener;
import com.alct.mdp.model.Goods;
import com.alct.mdp.model.Image;
import com.alct.mdp.model.Location;
import com.arpa.hndahesudintocctmsdriver.R;
import com.arpa.hndahesudintocctmsdriver.bean.BaseBean;
import com.arpa.hndahesudintocctmsdriver.bean.CarInfoBean;
import com.arpa.hndahesudintocctmsdriver.bean.StartOrderBean;
import com.arpa.hndahesudintocctmsdriver.bean.UploadBean;
import com.arpa.hndahesudintocctmsdriver.report.JTTProcess;
import com.arpa.hndahesudintocctmsdriver.request.HuoYuanRequset;
import com.arpa.hndahesudintocctmsdriver.request.OCRRequest;
import com.arpa.hndahesudintocctmsdriver.request.bean.LUInputBean;
import com.arpa.hndahesudintocctmsdriver.request.bean.UploadReceiptInputBean;
import com.arpa.hndahesudintocctmsdriver.util.BitmapUtil;
import com.arpa.hndahesudintocctmsdriver.util.MessageUtils;
import com.arpa.hndahesudintocctmsdriver.util.NfcUtils;
import com.arpa.hndahesudintocctmsdriver.util.alert.CustomDialog;
import com.arpa.hndahesudintocctmsdriver.util.alert.ToastUtil;
import com.arpa.hndahesudintocctmsdriver.util.cache.CacheGroup;
import com.arpa.hndahesudintocctmsdriver.util.file.FileUtil;
import com.arpa.hndahesudintocctmsdriver.util.file.ImageFileCompressUtil;
import com.arpa.hndahesudintocctmsdriver.util.http.RequsetCodeConstants;
import com.arpa.hndahesudintocctmsdriver.util.img.GetCarImageAlert;
import com.arpa.hndahesudintocctmsdriver.util.location.LocationGDUtil;
import com.arpa.hndahesudintocctmsdriver.util.location.LocationUtil;
import com.arpa.hndahesudintocctmsdriver.util.statusbar.StateStyleUtil;
import com.arpa.hndahesudintocctmsdriver.util.time.Timer;
import com.arpa.hndahesudintocctmsdriver.util.view.BaseAppCompatActivity;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.utils.CoordinateConverter;
import com.bumptech.glide.Glide;
import com.google.gson.Gson;
import com.luck.picture.lib.PictureSelector;
import com.luck.picture.lib.config.PictureConfig;
import com.luck.picture.lib.entity.LocalMedia;
import com.lxj.xpopup.XPopup;
import com.lxj.xpopup.util.SmartGlideImageLoader;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
public class ShangChuangImgActivityBC extends BaseAppCompatActivity {
private TextView submit, name_top, name_body, address, tips, tips_x;
private RelativeLayout getImg;
private ImageView res_img, img_icon, img_delete;
private String[] names = {"装货", "卸货", "回单"};
public static String[] TYPE_NAME = {"zhuanghuo", "xiehuo", "huidan"};
private int index = 0;
//
private Gson gson = new Gson();
//
private LUInputBean lub = new LUInputBean();
private UploadReceiptInputBean urib = new UploadReceiptInputBean();
private LocationGDUtil lgdu;
public LocationUtil lu;
private List<Integer> imgIds = new ArrayList<>();
private UploadBean ub;
private HuoYuanRequset hyr;
//
private GetCarImageAlert gia = new GetCarImageAlert();
private CustomDialog customDialog;
private int id = 0;
private boolean key = true;
private boolean keys = false;
private boolean locationKey = false;
private TextView tv_loaction;
private TempLoca tempLoca = new TempLoca(36.11944878,120.10315118,"中国山东省青岛市黄岛区铁峰山路","2023-09-23 11:19");
class TempLoca{
private double latitude;
private double longitude;
private String address;
private String time;
public TempLoca() {
}
public TempLoca(double latitude, double longitude, String address, String time) {
this.latitude = latitude;
this.longitude = longitude;
this.address = address;
this.time = time;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
}
@Override
public void msgMethod(Message m) {
super.msgMethod(m);
switch (m.what) {
case RequsetCodeConstants.SUCCESS:
if (CacheGroup.cacheList.get("upload") != null) {
Log.e("upload", CacheGroup.cacheList.get("upload"));
ub = gson.fromJson(CacheGroup.cacheList.remove("upload"), UploadBean.class);
if (ub.getCode() == 200) {
imgIds.add(ub.getData().getId());
Glide.with(con).load(ub.getData().getUrl()).into(res_img);
res_img.setVisibility(View.VISIBLE);
img_delete.setVisibility(View.VISIBLE);
img_icon.setVisibility(View.GONE);
key = false;
} else {
Toast.makeText(con, ub.getMsg(), Toast.LENGTH_SHORT).show();
}
CacheGroup.cacheList.remove("upload");
}
for (int i = 0; i < TYPE_NAME.length; i++) {
if (CacheGroup.cacheList.get(TYPE_NAME[i]) != null) {
BaseBean bb = gson.fromJson(CacheGroup.cacheList.get(TYPE_NAME[i]), BaseBean.class);
if (bb.getCode() == 200) {
if (index == 2) {
if (!keys){//装货回单
Toast.makeText(con, "上传成功", Toast.LENGTH_SHORT).show();
finish();
}
}
} else {
Toast.makeText(con, bb.getMsg(), Toast.LENGTH_SHORT).show();
}
CacheGroup.cacheList.remove(TYPE_NAME[i]);
break;
}
}
if (CacheGroup.cacheList.get("carName") != null) {
BaseBean bb = gson.fromJson(CacheGroup.cacheList.get("carName"), BaseBean.class);
if (bb.getCode() == 200) {
}
CacheGroup.cacheList.remove("carName");
}
if (CacheGroup.cacheList.get("carNum") != null) {
Log.e("upload", CacheGroup.cacheList.get("carNum"));
CarInfoBean ub = gson.fromJson(CacheGroup.cacheList.remove("carNum"), CarInfoBean.class);
if (ub.getCode() == 200 && ub.getData().getData().getPrism_keyValueInfo().size() > 0) {
String value = ub.getData().getData().getPrism_keyValueInfo().get(0).getValue();
String forceMatching = ub.getData().getForceMatching();
if ("1".equals(forceMatching)) {//是否强校验车牌号 1:强校验
if (sob.getData().getCarNumber().equals(value)) {
hyr.uploadFile(new File(path));
} else {
new MessageUtils().showCenMessage(ShangChuangImgActivityBC.this, "车牌号不匹配!", "请重新拍照或联系管理员");
}
} else {
hyr.uploadFile(new File(path));
}
} else {//识别失败后返回code500
if (index == 0) {//装卸货车辆需要识别车牌号){
Toast.makeText(con, "装货照片包含车牌号、三分之二车身或者装卸货场景。", Toast.LENGTH_SHORT).show();
} else if (index == 1) {
Toast.makeText(con, "卸货照片包含车牌号、三分之二车身或者装卸货场景。", Toast.LENGTH_SHORT).show();
}
}
CacheGroup.cacheList.remove("carNum");
}
break;
case 14://定位成功
locationKey = true;
customDialog.dismiss();
tv_loaction.setText("定位成功");
tv_loaction.setTextColor(getResources().getColor(R.color.theme_color, null));
latLng = convertGPSToBaidu(new LatLng(lgdu.getLatitude(), lgdu.getLongitude()));
initLocation();
break;
case 16://定位失败
locationKey = false;
customDialog.dismiss();
tv_loaction.setText("定位失败,点击重试");
tv_loaction.setTextColor(getResources().getColor(R.color.loaction_no_color, null));
Toast.makeText(con, "定位失败,请确认开启定位后重试!", Toast.LENGTH_LONG).show();
//定位结果接收
//finish();
break;
case 15:
break;
case ImageFileCompressUtil.COMPRESS_SUCCESS:
path = (String) m.obj;
Log.e("res:", "选定图片结果");
Log.e("res:", path);
//选定图片结果
// if(index==1 || index==2){
// new OCRRequest().OCRPlateLicense(con,hd,new File(path));
// }
if (index == 0 || index == 1) {//装卸货车辆需要识别车牌号
new OCRRequest().OCRCarPlateLicense(con, hd, new File(path));
} else {
hyr.uploadFile(new File(path));
}
break;
default:
break;
}
}
private LatLng latLng;
public LatLng convertGPSToBaidu(LatLng srLatLng) {
CoordinateConverter converter = new CoordinateConverter();
converter.from(CoordinateConverter.CoordType.COMMON);
converter.coord(srLatLng);
return converter.convert();
}
private String wid;
private int h_type;
String sobStr = "";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StateStyleUtil.stateTextColor(this);
setContentView(R.layout.activity_shangchuan_bc);
con = this;
submit = findViewById(R.id.submit);
name_top = findViewById(R.id.name_top);
name_body = findViewById(R.id.name_body);
address = findViewById(R.id.address);
getImg = findViewById(R.id.getImg);
res_img = findViewById(R.id.res_img);
img_icon = findViewById(R.id.img_icon);
img_delete = findViewById(R.id.img_delete);
tv_loaction = findViewById(R.id.tv_loaction);
tips = findViewById(R.id.tips);
tips_x = findViewById(R.id.tips_x);
Bundle ins = getIntent().getExtras();
index = ins.getInt("type");
wid = ins.getString("wid");
h_type = ins.getInt("h_type");
keys = ins.getBoolean("keys");
sobStr = getIntent().getExtras().getString("sob");
//Log.e("---sdwStr--",sdwStr);
sob = new Gson().fromJson(sobStr, StartOrderBean.class);
initView(null);
customDialog = new CustomDialog(con, "正在定位当前位置...");
customDialog.show();
lgdu = new LocationGDUtil(con, hd);
//启动定位
lgdu.onCreate();
tv_loaction.setOnClickListener(v -> {
if (!locationKey) {
customDialog.show();
lgdu.onCreate();
}
});
hyr = new HuoYuanRequset(con, hd);
}
public void initData() {
//nfc初始化设置
NfcUtils nfcUtils = new NfcUtils(this);
}
@Override
public void initView(Object obj) {
super.initView(obj);
name_top.setText("上传" + names[index] + "照片");
name_body.setText(names[index] + "照片");
if (index == 1) {
tips.setVisibility(View.VISIBLE);
tips_x.setVisibility(View.VISIBLE);
}
submit.setOnClickListener(v -> {
if (imgIds.size() != 0) {
typeRequest();
} else {
Toast.makeText(con, "请先上传一张图片", Toast.LENGTH_SHORT).show();
}
});
getImg.setOnClickListener(v -> {
if (key) {
Log.e("--imgIds.size()--", imgIds.size() + "");
gia.showPopueWindow(this, true);
} else {
new XPopup.Builder(con)
.asImageViewer(res_img, ub.getData().getUrl(), new SmartGlideImageLoader(R.mipmap.ic_launcher))
.show();
// new XPopup.Builder(con)
// .asImageViewer(res_img, ub.getData().getUrl(), true, -1, -1, 50, false,new CertificatesActivity.ImageLoader())
// .show();
Toast.makeText(con, "查看了照片", Toast.LENGTH_SHORT).show();
}
});
img_delete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
imgIds = new ArrayList<>();
ub = new UploadBean();
res_img.setVisibility(View.GONE);
img_delete.setVisibility(View.GONE);
img_icon.setVisibility(View.VISIBLE);
key = true;
}
});
}
String path;
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 12 && resultCode == RESULT_OK) {
if (null == gia.getFile()) {
new ToastUtil(con, Gravity.CENTER, "图片选择失败").show(Toast.LENGTH_SHORT);
return;
}
path = gia.getFile().getPath();
Log.e("图片地址:", path);
gia.dis();
ImageFileCompressUtil.imageFileCompress(con, new File(path), hd);
} else if (requestCode == PictureConfig.CHOOSE_REQUEST && resultCode == RESULT_OK) {
List<LocalMedia> imgs = PictureSelector.obtainMultipleResult(data);
if (imgs != null && imgs.size() > 0) {
LocalMedia image = imgs.get(0);
String paths = image.getAndroidQToPath();
if (TextUtils.isEmpty(paths)) {
paths = image.getPath();
}
path = paths;
Log.e("图片地址:", path);
gia.dis();
ImageFileCompressUtil.imageFileCompress(con, new File(path), hd);
}
}
}
public void initLocation() {
address.setText(lgdu.getAddress());
}
public void typeRequest() {
// for(int i=0;i<imgIds.size();i++){
// Log.e("--imgIds--",imgIds.get(i)+"");
// }
switch (index) {
case 0:
//装货
if (imgIds != null && imgIds.size() > 0) {
lub.setLatitude(lgdu.getLatitude() + "");
lub.setLongitude(lgdu.getLongitude() + "");
lub.setLocationAddress(lgdu.getAddress());
lub.setImageId(imgIds);
lub.setWaybillId(wid);
Log.e("--装货信息", gson.toJson(lub));
if (locationKey) {//高德定位
if (keys) {
nfc();
loadInfo();
// up_traffic_start();
// up_image_z();
}
} else {
Toast.makeText(con, "定位异常,请重新定位", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(con, "图片上传异常,请重新上传", Toast.LENGTH_SHORT).show();
}
break;
case 1:
if (imgIds != null && imgIds.size() > 0) {
//卸货
lub.setLatitude(tempLoca.getLatitude() + "");
lub.setLongitude(tempLoca.getLongitude() + "");
lub.setLocationAddress(tempLoca.getAddress());
lub.setImageId(imgIds);
lub.setWaybillId(wid);
Log.e("--卸货信息", gson.toJson(lub));
if (locationKey) {
if (keys) {
nfc();
uploadInfo();
}
} else {
Toast.makeText(con, "定位异常,请重新定位", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(con, "图片上传异常,请重新上传", Toast.LENGTH_SHORT).show();
}
break;
case 2:
if (imgIds != null && imgIds.size() > 0) {//卸货回单
//上传回单
urib.setLatitude(lgdu.getLatitude() + "");
urib.setLongitude(lgdu.getLongitude() + "");
urib.setLocationAddress(lgdu.getAddress());
//装卸货类型
urib.setType(h_type + 1);
//回单id 数组
urib.setReceiptId(imgIds);
//子运运单ID
urib.setWaybillId(wid);
Log.e("--回单信息", gson.toJson(urib));
if (locationKey) {
if (index == 2 && keys) {
up_trafficSign();
up_trafficReceipt();
receipt_image();
}
hyr.receipt(urib);
} else {
Toast.makeText(con, "定位异常,请重新定位", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(con, "图片上传异常,请重新上传", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
private StartOrderBean sob;
public void nfc() {
// if(sob.getData().getNfcId().equals(nfcStr)){
// Toast.makeText(con,"nfcId匹配失败",Toast.LENGTH_LONG).show();
// }
if ("".equals(sob.getData().getNfcId()) || sob.getData().getNfcId() == null) {
return;
}
MDPLocationCollectionManager.checkNfc(con, sob.getData().getShippingNoteNumber(),
sob.getData().getNfcId(), new OnResultListener() {
@Override
public void onSuccess() {
Toast.makeText(con, "nfcId匹配成功", Toast.LENGTH_LONG).show();
}
@Override
public void onFailure(String s, String s1) {
Log.e("不匹配", "" + s + s1);
}
});
}
//上传安联-签收
public void up_trafficSign() {
//安联
Location l = new Location();
l.setBaiduLongitude(tempLoca.longitude);
l.setBaiduLatitude(tempLoca.latitude);
l.setLocation(tempLoca.getAddress());
l.setTime(tempLoca.getTime());
List<Goods> gs = new ArrayList<>();
for (StartOrderBean.DataDTO.WayChildrenDTO wayChild : sob.getData().getWayChildren()) {
if (wid.equals(wayChild.getId() + "")) {
for (StartOrderBean.DataDTO.WayChildrenDTO.GoodsDTO good : wayChild.getGoods()) {
Goods g = new Goods();
g.setGoodsName(good.getGoodName());
g.setUnit(good.getGoodUnit());
g.setItemNo(good.getId());
//实收
g.setQuantity(1);
//应收
g.setReceivedQuantity(1);
//破损
g.setDamageQuantity(1);
//丢失
g.setQuantity(1);
}
}
}
MDPLocationCollectionManager.sign(con, sob.getData().getShippingNoteNumber(), l, gs, new OnResultListener() {
@Override
public void onSuccess() {
Log.e("上报安联", "签收成功");
}
@Override
public void onFailure(String s, String s1) {
Log.e("上报安联失败(签收):", s + s1);
}
});
}
//上传安联-回单
public void up_trafficReceipt() {
//安联
Location l = new Location();
l.setBaiduLongitude(tempLoca.longitude);
l.setBaiduLatitude(tempLoca.latitude);
l.setLocation(tempLoca.getAddress());
l.setTime(tempLoca.getTime());
MDPLocationCollectionManager.pod(con, sob.getData().getShippingNoteNumber(), l, new OnResultListener() {
@Override
public void onSuccess() {
Log.e("上报安联", "回单上传成功");
}
@Override
public void onFailure(String s, String s1) {
Log.e("上报安联失败(回单):", s + s1);
}
});
}
public void up_image_z() {
///storage/emulated/0/Android/data/com.oneclouds.wangluohuoyun/files/Pictures/163124593063154.jpg
File file = new File(path);
Image image = new Image();
String base = BitmapUtil.imageToBase64(path);
image.setFileData("data:image/" + FileUtil.lastName(file) + ";base64," + base);
image.setFileExt(FileUtil.lastName(file));
image.setFileName(FileUtil.fileName(file));
image.setImageTakenDate(Timer.getTimerT());
image.setBaiduLongitude(latLng.longitude);
image.setBaiduLatitude(latLng.latitude);
image.setLocation(lgdu.getAddress());
MDPLocationCollectionManager.uploadPickupImage(con, sob.getData().getShippingNoteNumber(), image, new OnResultListener() {
@Override
public void onSuccess() {
Log.e("上报安联", "装货照片上传成功");
Toast.makeText(con, "上传成功", Toast.LENGTH_SHORT).show();
finish();
}
@Override
public void onFailure(String s, String s1) {
Log.e("上报安联失败(装货照片):", s + s1);
// SPUtil.insSP(con,"make","装货",sob.getData().getShippingNoteNumber());
// SPUtil.insSP(con,"make","装货-"+sob.getData().getShippingNoteNumber(),gson.toJson(image));
// Intent serviceIn=new Intent(con, MakeUpAlService.class);
// startService(serviceIn);
}
});
}
public void up_image() {
File file = new File(path);
Image image = new Image();
String base = BitmapUtil.imageToBase64(path);
image.setFileData("data:image/" + FileUtil.lastName(file) + ";base64," + base);
image.setFileExt(FileUtil.lastName(file));
image.setFileName(FileUtil.fileName(file));
image.setImageTakenDate(tempLoca.getTime());
image.setBaiduLongitude(tempLoca.longitude);
image.setBaiduLatitude(tempLoca.latitude);
image.setLocation(tempLoca.getAddress());
MDPLocationCollectionManager.uploadUnloadImage(con, sob.getData().getShippingNoteNumber(), image, new OnResultListener() {
@Override
public void onSuccess() {
Log.e("上报安联", "卸货照片上传成功");
Toast.makeText(con, "上传成功", Toast.LENGTH_SHORT).show();
finish();
}
@Override
public void onFailure(String s, String s1) {
Log.e("上报安联失败(卸货照片):", s + s1);
// SPUtil.insSP(con,"make","卸货",sob.getData().getShippingNoteNumber());
// SPUtil.insSP(con,"make","卸货-"+sob.getData().getShippingNoteNumber(),gson.toJson(image));
// Intent serviceIn=new Intent(con, MakeUpAlService.class);
// startService(serviceIn);
}
});
}
public void receipt_image() {
///storage/emulated/0/Android/data/com.oneclouds.wangluohuoyun/files/Pictures/163124593063154.jpg
File file = new File(path);
Image image = new Image();
String base = BitmapUtil.imageToBase64(path);
image.setFileData("data:image/" + FileUtil.lastName(file) + ";base64," + base);
image.setFileExt(FileUtil.lastName(file));
image.setFileName(FileUtil.fileName(file));
image.setImageTakenDate(tempLoca.getTime());
image.setBaiduLongitude(tempLoca.longitude);
image.setBaiduLatitude(tempLoca.latitude);
image.setLocation(tempLoca.getAddress());
MDPLocationCollectionManager.uploadPODImage(con, sob.getData().getShippingNoteNumber(), image, new OnResultListener() {
@Override
public void onSuccess() {
Log.e("上报安联", "回单照片上传成功");
Toast.makeText(con, "上传成功", Toast.LENGTH_SHORT).show();
finish();
}
@Override
public void onFailure(String s, String s1) {
Log.e("上报安联失败(回单照片):", s + s1);
// SPUtil.insSP(con,"make","回单",sob.getData().getShippingNoteNumber());
//// SPUtil.insSP(con,"make","回单-"+sob.getData().getShippingNoteNumber(),gson.toJson(image));
//// Intent serviceIn=new Intent(con, MakeUpAlService.class);
//// startService(serviceIn);
}
});
}
@Override
protected void onResume() {
super.onResume();
//开启前台调度系统
//NfcUtils.mNfcAdapter.enableForegroundDispatch(this, NfcUtils.mPendingIntent, NfcUtils.mIntentFilter, NfcUtils.mTechList);
}
@Override
protected void onPause() {
super.onPause();
//关闭前台调度系统
//NfcUtils.mNfcAdapter.disableForegroundDispatch(this);
}
String nfcStr = "";
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
//当该Activity接收到NFC标签时,运行该方法
//调用工具方法,读取NFC数据
try {
nfcStr = NfcUtils.readNFCId(intent);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Log.e("nfc", nfcStr);
}
/**
* 上传安联和交通厅,平台-装货
*/
private void loadInfo() {
//安联
if (sob.getData().getReportAlct() == 1) {
Location l = new Location();
l.setBaiduLongitude(latLng.longitude);
l.setBaiduLatitude(latLng.latitude);
l.setLocation(lgdu.getAddress());
l.setTime(Timer.getTimerT());
MDPLocationCollectionManager.pickup(con, sob.getData().getShippingNoteNumber(), l, new OnResultListener() {
@Override
public void onSuccess() {
Log.e("上报安联", "装货上传成功");
//交通厅
if (sob.getData().getReport() == 1) {
JTTProcess.start(con, sob, "");
}
//装货状态
hyr.loading(lub);
//装货照片
up_image_z();
}
@Override
public void onFailure(String s, String s1) {
Log.e("上报安联失败(装货):", s + s1);
new MessageUtils().showCenMessage(con, s1);
}
});
}
}
/**
* 上传安联和交通厅,平台-卸货
*/
private void uploadInfo() {
//安联
if (sob.getData().getReportAlct() == 1) {
Location l = new Location();
l.setBaiduLongitude(tempLoca.longitude);
l.setBaiduLatitude(tempLoca.latitude);
l.setLocation(tempLoca.getAddress());
l.setTime(tempLoca.getTime());
Log.e("-安联卸货信息-", gson.toJson(l));
MDPLocationCollectionManager.unload(con, sob.getData().getShippingNoteNumber(), l, new OnResultListener() {
@Override
public void onSuccess() {
Log.e("上报安联", "卸货上传成功");
//交通厅
if (sob.getData().getReport() == 1) {
JTTProcess.stop(con, sob, "");
}
//卸货状态-平台
hyr.dischargeCargo(lub);
//卸货照片-安联
up_image();
}
@Override
public void onFailure(String s, String s1) {
Log.e("上报安联失败(卸货):", s + s1);
new MessageUtils().showCenMessage(con, s1);
}
});
}
}
}
@@ -1,21 +1,14 @@
package com.arpa.hndahesudintocctmsdriver.ui.news; package com.arpa.hndahesudintocctmsdriver.ui.news;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment;
import android.provider.Settings;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import com.arpa.hndahesudintocctmsdriver.R; import com.arpa.hndahesudintocctmsdriver.R;
import com.arpa.hndahesudintocctmsdriver.util.alert.ToastUtil;
import com.arpa.hndahesudintocctmsdriver.util.statusbar.StateStyleUtil; import com.arpa.hndahesudintocctmsdriver.util.statusbar.StateStyleUtil;
import com.arpa.hndahesudintocctmsdriver.util.view.BaseAppCompatActivity; import com.arpa.hndahesudintocctmsdriver.util.view.BaseAppCompatActivity;
import com.arpa.hndahesudintocctmsdriver.util.view.BottomTabUtil; import com.arpa.hndahesudintocctmsdriver.util.view.BottomTabUtil;
import com.dahe.mylibrary.utils.ToastUtils;
/** /**
* @author hlh * @author hlh
@@ -34,33 +27,6 @@ public class NewActivity extends BaseAppCompatActivity {
fs[0] =new NewsFragment(); fs[0] =new NewsFragment();
BottomTabUtil bt =new BottomTabUtil(this,R.id.body, fs); BottomTabUtil bt =new BottomTabUtil(this,R.id.body, fs);
bt.selectItem(fs[0]); bt.selectItem(fs[0]);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if (!Environment.isExternalStorageManager()) {
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
intent.setData(Uri.parse("package:" + getPackageName()));
this.startActivityForResult(intent, 1024);
}
}
} }
private boolean isRefuse = false;
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 1024 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// 检查是否有权限
if (Environment.isExternalStorageManager()) {
isRefuse = false;
ToastUtils.showToast(this,"授权成功");
// 授权成功
} else {
isRefuse = true;
ToastUtils.showToast(this,"授权失败");
// 授权失败
}
}
}
} }
@@ -51,9 +51,6 @@ public class AdapterAlls extends RecyclerView.Adapter<AdapterAlls.ViewHolder> {
} }
public void add(List<ManyBean> addMessageList) { public void add(List<ManyBean> addMessageList) {
if (object==null){
return;
}
//增加数据 //增加数据
int position = object.size(); int position = object.size();
object.addAll(position, addMessageList); object.addAll(position, addMessageList);
@@ -70,27 +70,13 @@ public class GetCarImageAlert {
.permissions(Manifest.permission.CAMERA) .permissions(Manifest.permission.CAMERA)
.request((allGranted, grantedList, deniedList) -> { .request((allGranted, grantedList, deniedList) -> {
if (allGranted) { if (allGranted) {
openCam(act); file=ImageGetUtil.createImageFile(act);
// file=ImageGetUtil.createImageFile(act); ImageGetUtil.cameraAlbumGetImage(act,file);
// ImageGetUtil.cameraAlbumGetImage(act,file);
} else { } else {
Toast.makeText(act.getBaseContext(), "开启权限失败,请手动开启权限", Toast.LENGTH_LONG).show(); Toast.makeText(act.getBaseContext(), "开启权限失败,请手动开启权限", Toast.LENGTH_LONG).show();
} }
}); });
}); });
img.setOnClickListener(v -> {
if (!key){
PermissionX.init(act)
.permissions(Manifest.permission.CAMERA)
.request((allGranted, grantedList, deniedList) -> {
if (allGranted) {
openCam(act);
} else {
Toast.makeText(act.getBaseContext(), "开启权限失败,请手动开启权限", Toast.LENGTH_LONG).show();
}
});
}
});
btn_quxiao.setOnClickListener(v -> popupWindow.dismiss()); btn_quxiao.setOnClickListener(v -> popupWindow.dismiss());
//popupWindow消失屏幕变为不透明 //popupWindow消失屏幕变为不透明
popupWindow.setOnDismissListener(() -> { popupWindow.setOnDismissListener(() -> {
@@ -113,13 +99,4 @@ public class GetCarImageAlert {
popupWindow.dismiss(); popupWindow.dismiss();
} }
private void openCam(AppCompatActivity act){
file=ImageGetUtil.createImageFile(act);
if (file!=null){
ImageGetUtil.cameraAlbumGetImage(act,file);
}else{
Toast.makeText(act.getBaseContext(), "路径创建失败,请清除缓存后重试", Toast.LENGTH_LONG).show();
}
}
} }
@@ -55,13 +55,13 @@
android:layout_width="@dimen/dp_90" android:layout_width="@dimen/dp_90"
android:layout_height="@dimen/dp_90" android:layout_height="@dimen/dp_90"
android:background="#EEEEEE"> android:background="#EEEEEE">
<ImageView <ImageView
android:layout_width="@dimen/dp_23" android:layout_width="@dimen/dp_23"
android:layout_height="@dimen/dp_23" android:layout_height="@dimen/dp_23"
android:layout_centerInParent="true" android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:scaleType="fitXY" android:scaleType="fitXY"
android:src="@mipmap/up_img" /> android:src="@mipmap/up_img"/>
</RelativeLayout> </RelativeLayout>
<RelativeLayout <RelativeLayout
android:layout_marginLeft="@dimen/dp_8" android:layout_marginLeft="@dimen/dp_8"
@@ -118,7 +118,6 @@
android:background="@drawable/bg_bai" android:background="@drawable/bg_bai"
android:elevation="@dimen/dp_1"> android:elevation="@dimen/dp_1">
<RelativeLayout <RelativeLayout
android:visibility="gone"
android:id="@+id/cow1" android:id="@+id/cow1"
android:layout_marginBottom="@dimen/dp_10" android:layout_marginBottom="@dimen/dp_10"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -131,28 +130,28 @@
android:textColor="#ffc4c4ce" android:textColor="#ffc4c4ce"
android:textSize="@dimen/sp_13" android:textSize="@dimen/sp_13"
/> />
<EditText <EditText
android:id="@+id/value1" android:id="@+id/value1"
android:layout_alignParentRight="true"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginLeft="@dimen/dp_30"
android:background="@null"
android:ellipsize="end"
android:gravity="right"
android:hint="点击进行手动输入"
android:maxLines="1"
android:textColor="#ff999999" android:textColor="#ff999999"
android:textSize="@dimen/sp_13" /> android:textSize="@dimen/sp_13"
android:maxLines="1"
android:hint="点击进行手动输入"
android:ellipsize="end"
android:layout_marginLeft="@dimen/dp_30"
android:gravity="right"
android:background="@null"
/>
</RelativeLayout> </RelativeLayout>
<View <View
android:visibility="gone"
android:id="@+id/vs" android:id="@+id/vs"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/dp_1" android:layout_height="@dimen/dp_1"
android:background="@drawable/bottom_xu"/> android:background="@drawable/bottom_xu"/>
<RelativeLayout <RelativeLayout
android:layout_marginTop="@dimen/dp_10"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<TextView <TextView
@@ -1,175 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@drawable/bg_theme"
android:id="@+id/activity_shangchuan">
<ImageView
android:layout_marginTop="@dimen/dp_16"
android:layout_width="@dimen/dp_300"
android:layout_height="@dimen/dp_207"
android:src="@mipmap/top_creativity"
android:layout_centerHorizontal="true"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_marginTop="@dimen/dp_58"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/return_btn"
android:layout_marginLeft="@dimen/dp_30"
android:layout_width="@dimen/dp_40"
android:layout_height="@dimen/dp_31"
android:src="@mipmap/return_lefts"
android:padding="@dimen/dp_10"
android:scaleType="fitXY"/>
<TextView
android:id="@+id/tv_loaction"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/sp_14"
android:text="定位成功"
android:layout_alignParentRight="true"
android:layout_marginRight="@dimen/dp_30"
android:layout_centerVertical="true"
android:padding="@dimen/dp_5"
android:textColor="@color/theme_color"/>
</RelativeLayout>
<TextView
android:layout_marginLeft="@dimen/dp_38"
android:layout_marginTop="@dimen/dp_8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="补传"
android:textColor="#ff000000"
android:textSize="@dimen/sp_23"
/>
<TextView
android:id="@+id/name_top"
android:layout_marginLeft="@dimen/dp_38"
android:layout_marginTop="@dimen/dp_8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="上传卸货照片"
android:textColor="#ff000000"
android:textSize="@dimen/sp_23"
/>
<androidx.cardview.widget.CardView
android:id="@+id/getImg1"
android:layout_marginTop="@dimen/dp_33"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_38"
android:layout_marginRight="@dimen/dp_38"
app:cardCornerRadius="@dimen/dp_8">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/getImg"
android:layout_marginLeft="@dimen/dp_11"
android:layout_marginTop="@dimen/dp_13"
android:layout_marginBottom="@dimen/dp_13"
android:layout_width="@dimen/dp_90"
android:layout_height="@dimen/dp_90"
android:background="#EEEEEE">
<ImageView
android:id="@+id/res_img"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="@+id/img_icon"
android:layout_width="@dimen/dp_23"
android:layout_height="@dimen/dp_23"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:src="@mipmap/up_img"/>
<ImageView
android:id="@+id/img_delete"
android:layout_alignParentRight="true"
android:layout_width="@dimen/dp_25"
android:layout_height="@dimen/dp_25"
android:src="@mipmap/icon_delete"
android:padding="@dimen/dp_3"
android:visibility="gone"/>
</RelativeLayout>
<LinearLayout
android:layout_marginTop="@dimen/dp_13"
android:layout_marginLeft="@dimen/dp_8"
android:layout_marginRight="@dimen/dp_10"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_marginTop="@dimen/dp_7"
android:id="@+id/name_body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="卸货照片"
android:textColor="#ff000000"
android:textSize="@dimen/sp_13"
/>
<TextView
android:layout_marginTop="@dimen/dp_13"
android:id="@+id/address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ff999999"
android:text=""
android:textSize="@dimen/sp_13" />
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
<LinearLayout
android:layout_marginTop="@dimen/dp_10"
android:layout_marginLeft="@dimen/dp_38"
android:layout_marginRight="@dimen/dp_38"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tips_x"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="*"
android:textColor="#E61829"
android:visibility="gone"/>
<TextView
android:id="@+id/tips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="卸货照片包含车牌号、三分之二车身或者卸货场景"
android:textColor="#E61829"
android:visibility="gone"/>
</LinearLayout>
<androidx.cardview.widget.CardView
android:layout_marginTop="@dimen/dp_33"
android:layout_marginLeft="@dimen/dp_38"
android:layout_marginRight="@dimen/dp_38"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_42"
app:cardCornerRadius="@dimen/dp_21"
app:cardBackgroundColor="@color/red">
<TextView
android:id="@+id/submit"
android:layout_alignParentRight="true"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="提交"
android:textColor="#fff"
android:textSize="@dimen/sp_15"
android:gravity="center"
/>
</androidx.cardview.widget.CardView>
</LinearLayout>
</RelativeLayout>
-17
View File
@@ -99,8 +99,6 @@
android:textSize="@dimen/sp_17" android:textSize="@dimen/sp_17"
android:background="@null" android:background="@null"
android:layout_marginBottom="@dimen/dp_3"/> android:layout_marginBottom="@dimen/dp_3"/>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:layout_marginTop="@dimen/dp_8" android:layout_marginTop="@dimen/dp_8"
@@ -124,7 +122,6 @@
android:progressDrawable="@drawable/par_bg" android:progressDrawable="@drawable/par_bg"
/> />
<TextView <TextView
android:id="@+id/tvContent"
android:layout_marginTop="@dimen/dp_6" android:layout_marginTop="@dimen/dp_6"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@@ -134,20 +131,6 @@
android:layout_gravity="center" android:layout_gravity="center"
/> />
</LinearLayout> </LinearLayout>
<Button
android:visibility="gone"
android:layout_marginLeft="@dimen/dp_18"
android:layout_marginRight="@dimen/dp_18"
android:id="@+id/tvOk"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="立即安装"
android:textColor="@color/theme_color"
android:textSize="@dimen/sp_17"
android:background="@null"
android:layout_marginBottom="@dimen/dp_13"/>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/force_box" android:id="@+id/force_box"
+424
View File
@@ -0,0 +1,424 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<dimen name="common_margin">@dimen/dp_15</dimen>
<dimen name="dp_m_60">-256.6667dp</dimen>
<dimen name="dp_m_50">-213.8889dp</dimen>
<dimen name="dp_m_30">-128.3333dp</dimen>
<dimen name="dp_m_20">-85.5556dp</dimen>
<dimen name="dp_m_12">-51.3333dp</dimen>
<dimen name="dp_m_10">-42.7778dp</dimen>
<dimen name="dp_m_8">-34.2222dp</dimen>
<dimen name="dp_m_5">-21.3889dp</dimen>
<dimen name="dp_m_2">-8.5556dp</dimen>
<dimen name="dp_m_1">-4.2778dp</dimen>
<dimen name="dp_0">0.0000dp</dimen>
<dimen name="dp_0_1">0.4278dp</dimen>
<dimen name="dp_0_5">2.1389dp</dimen>
<dimen name="dp_1">4.2778dp</dimen>
<dimen name="dp_1_5">6.4167dp</dimen>
<dimen name="dp_2">8.5556dp</dimen>
<dimen name="dp_2_5">10.6944dp</dimen>
<dimen name="dp_3">12.8333dp</dimen>
<dimen name="dp_3_5">14.9722dp</dimen>
<dimen name="dp_4">17.1111dp</dimen>
<dimen name="dp_4_5">19.2500dp</dimen>
<dimen name="dp_5">21.3889dp</dimen>
<dimen name="dp_6">25.6667dp</dimen>
<dimen name="dp_7">29.9444dp</dimen>
<dimen name="dp_8">34.2222dp</dimen>
<dimen name="dp_9">38.5000dp</dimen>
<dimen name="dp_10">42.7778dp</dimen>
<dimen name="dp_11">47.0556dp</dimen>
<dimen name="dp_12">51.3333dp</dimen>
<dimen name="dp_13">55.6111dp</dimen>
<dimen name="dp_14">59.8889dp</dimen>
<dimen name="dp_15">64.1667dp</dimen>
<dimen name="dp_16">68.4444dp</dimen>
<dimen name="dp_17">72.7222dp</dimen>
<dimen name="dp_18">77.0000dp</dimen>
<dimen name="dp_19">81.2778dp</dimen>
<dimen name="dp_20">85.5556dp</dimen>
<dimen name="dp_21">89.8333dp</dimen>
<dimen name="dp_22">94.1111dp</dimen>
<dimen name="dp_23">98.3889dp</dimen>
<dimen name="dp_24">102.6667dp</dimen>
<dimen name="dp_25">106.9444dp</dimen>
<dimen name="dp_26">111.2222dp</dimen>
<dimen name="dp_27">115.5000dp</dimen>
<dimen name="dp_28">119.7778dp</dimen>
<dimen name="dp_29">124.0556dp</dimen>
<dimen name="dp_30">128.3333dp</dimen>
<dimen name="dp_31">132.6111dp</dimen>
<dimen name="dp_32">136.8889dp</dimen>
<dimen name="dp_33">141.1667dp</dimen>
<dimen name="dp_34">145.4444dp</dimen>
<dimen name="dp_35">149.7222dp</dimen>
<dimen name="dp_36">154.0000dp</dimen>
<dimen name="dp_37">158.2778dp</dimen>
<dimen name="dp_38">162.5556dp</dimen>
<dimen name="dp_39">166.8333dp</dimen>
<dimen name="dp_40">171.1111dp</dimen>
<dimen name="dp_41">175.3889dp</dimen>
<dimen name="dp_42">179.6667dp</dimen>
<dimen name="dp_43">183.9444dp</dimen>
<dimen name="dp_44">188.2222dp</dimen>
<dimen name="dp_45">192.5000dp</dimen>
<dimen name="dp_46">196.7778dp</dimen>
<dimen name="dp_47">201.0556dp</dimen>
<dimen name="dp_48">205.3333dp</dimen>
<dimen name="dp_49">209.6111dp</dimen>
<dimen name="dp_50">213.8889dp</dimen>
<dimen name="dp_51">218.1667dp</dimen>
<dimen name="dp_52">222.4444dp</dimen>
<dimen name="dp_53">226.7222dp</dimen>
<dimen name="dp_54">231.0000dp</dimen>
<dimen name="dp_55">235.2778dp</dimen>
<dimen name="dp_56">239.5556dp</dimen>
<dimen name="dp_57">243.8333dp</dimen>
<dimen name="dp_58">248.1111dp</dimen>
<dimen name="dp_59">252.3889dp</dimen>
<dimen name="dp_60">256.6667dp</dimen>
<dimen name="dp_61">260.9444dp</dimen>
<dimen name="dp_62">265.2222dp</dimen>
<dimen name="dp_63">269.5000dp</dimen>
<dimen name="dp_64">273.7778dp</dimen>
<dimen name="dp_65">278.0556dp</dimen>
<dimen name="dp_66">282.3333dp</dimen>
<dimen name="dp_67">286.6111dp</dimen>
<dimen name="dp_68">290.8889dp</dimen>
<dimen name="dp_69">295.1667dp</dimen>
<dimen name="dp_70">299.4444dp</dimen>
<dimen name="dp_71">303.7222dp</dimen>
<dimen name="dp_72">308.0000dp</dimen>
<dimen name="dp_73">312.2778dp</dimen>
<dimen name="dp_74">316.5556dp</dimen>
<dimen name="dp_75">320.8333dp</dimen>
<dimen name="dp_76">325.1111dp</dimen>
<dimen name="dp_77">329.3889dp</dimen>
<dimen name="dp_78">333.6667dp</dimen>
<dimen name="dp_79">337.9444dp</dimen>
<dimen name="dp_80">342.2222dp</dimen>
<dimen name="dp_81">346.5000dp</dimen>
<dimen name="dp_82">350.7778dp</dimen>
<dimen name="dp_83">355.0556dp</dimen>
<dimen name="dp_84">359.3333dp</dimen>
<dimen name="dp_85">363.6111dp</dimen>
<dimen name="dp_86">367.8889dp</dimen>
<dimen name="dp_87">372.1667dp</dimen>
<dimen name="dp_88">376.4444dp</dimen>
<dimen name="dp_89">380.7222dp</dimen>
<dimen name="dp_90">385.0000dp</dimen>
<dimen name="dp_91">389.2778dp</dimen>
<dimen name="dp_92">393.5556dp</dimen>
<dimen name="dp_93">397.8333dp</dimen>
<dimen name="dp_94">402.1111dp</dimen>
<dimen name="dp_95">406.3889dp</dimen>
<dimen name="dp_96">410.6667dp</dimen>
<dimen name="dp_97">414.9444dp</dimen>
<dimen name="dp_98">419.2222dp</dimen>
<dimen name="dp_99">423.5000dp</dimen>
<dimen name="dp_100">427.7778dp</dimen>
<dimen name="dp_101">432.0556dp</dimen>
<dimen name="dp_102">436.3333dp</dimen>
<dimen name="dp_103">440.6111dp</dimen>
<dimen name="dp_104">444.8889dp</dimen>
<dimen name="dp_105">449.1667dp</dimen>
<dimen name="dp_106">453.4444dp</dimen>
<dimen name="dp_107">457.7222dp</dimen>
<dimen name="dp_108">462.0000dp</dimen>
<dimen name="dp_109">466.2778dp</dimen>
<dimen name="dp_110">470.5556dp</dimen>
<dimen name="dp_111">474.8333dp</dimen>
<dimen name="dp_112">479.1111dp</dimen>
<dimen name="dp_113">483.3889dp</dimen>
<dimen name="dp_114">487.6667dp</dimen>
<dimen name="dp_115">491.9444dp</dimen>
<dimen name="dp_116">496.2222dp</dimen>
<dimen name="dp_117">500.5000dp</dimen>
<dimen name="dp_118">504.7778dp</dimen>
<dimen name="dp_119">509.0556dp</dimen>
<dimen name="dp_120">513.3333dp</dimen>
<dimen name="dp_121">517.6111dp</dimen>
<dimen name="dp_122">521.8889dp</dimen>
<dimen name="dp_123">526.1667dp</dimen>
<dimen name="dp_124">530.4444dp</dimen>
<dimen name="dp_125">534.7222dp</dimen>
<dimen name="dp_126">539.0000dp</dimen>
<dimen name="dp_127">543.2778dp</dimen>
<dimen name="dp_128">547.5556dp</dimen>
<dimen name="dp_129">551.8333dp</dimen>
<dimen name="dp_130">556.1111dp</dimen>
<dimen name="dp_131">560.3889dp</dimen>
<dimen name="dp_132">564.6667dp</dimen>
<dimen name="dp_133">568.9444dp</dimen>
<dimen name="dp_134">573.2222dp</dimen>
<dimen name="dp_135">577.5000dp</dimen>
<dimen name="dp_136">581.7778dp</dimen>
<dimen name="dp_137">586.0556dp</dimen>
<dimen name="dp_138">590.3333dp</dimen>
<dimen name="dp_139">594.6111dp</dimen>
<dimen name="dp_140">598.8889dp</dimen>
<dimen name="dp_141">603.1667dp</dimen>
<dimen name="dp_142">607.4444dp</dimen>
<dimen name="dp_143">611.7222dp</dimen>
<dimen name="dp_144">616.0000dp</dimen>
<dimen name="dp_145">620.2778dp</dimen>
<dimen name="dp_146">624.5556dp</dimen>
<dimen name="dp_147">628.8333dp</dimen>
<dimen name="dp_148">633.1111dp</dimen>
<dimen name="dp_149">637.3889dp</dimen>
<dimen name="dp_150">641.6667dp</dimen>
<dimen name="dp_151">645.9444dp</dimen>
<dimen name="dp_152">650.2222dp</dimen>
<dimen name="dp_153">654.5000dp</dimen>
<dimen name="dp_154">658.7778dp</dimen>
<dimen name="dp_155">663.0556dp</dimen>
<dimen name="dp_156">667.3333dp</dimen>
<dimen name="dp_157">671.6111dp</dimen>
<dimen name="dp_158">675.8889dp</dimen>
<dimen name="dp_159">680.1667dp</dimen>
<dimen name="dp_160">684.4444dp</dimen>
<dimen name="dp_161">688.7222dp</dimen>
<dimen name="dp_162">693.0000dp</dimen>
<dimen name="dp_163">697.2778dp</dimen>
<dimen name="dp_164">701.5556dp</dimen>
<dimen name="dp_165">705.8333dp</dimen>
<dimen name="dp_166">710.1111dp</dimen>
<dimen name="dp_167">714.3889dp</dimen>
<dimen name="dp_168">718.6667dp</dimen>
<dimen name="dp_169">722.9444dp</dimen>
<dimen name="dp_170">727.2222dp</dimen>
<dimen name="dp_171">731.5000dp</dimen>
<dimen name="dp_172">735.7778dp</dimen>
<dimen name="dp_173">740.0556dp</dimen>
<dimen name="dp_174">744.3333dp</dimen>
<dimen name="dp_175">748.6111dp</dimen>
<dimen name="dp_176">752.8889dp</dimen>
<dimen name="dp_177">757.1667dp</dimen>
<dimen name="dp_178">761.4444dp</dimen>
<dimen name="dp_179">765.7222dp</dimen>
<dimen name="dp_180">770.0000dp</dimen>
<dimen name="dp_181">774.2778dp</dimen>
<dimen name="dp_182">778.5556dp</dimen>
<dimen name="dp_183">782.8333dp</dimen>
<dimen name="dp_184">787.1111dp</dimen>
<dimen name="dp_185">791.3889dp</dimen>
<dimen name="dp_186">795.6667dp</dimen>
<dimen name="dp_187">799.9444dp</dimen>
<dimen name="dp_188">804.2222dp</dimen>
<dimen name="dp_189">808.5000dp</dimen>
<dimen name="dp_190">812.7778dp</dimen>
<dimen name="dp_191">817.0556dp</dimen>
<dimen name="dp_192">821.3333dp</dimen>
<dimen name="dp_193">825.6111dp</dimen>
<dimen name="dp_194">829.8889dp</dimen>
<dimen name="dp_195">834.1667dp</dimen>
<dimen name="dp_196">838.4444dp</dimen>
<dimen name="dp_197">842.7222dp</dimen>
<dimen name="dp_198">847.0000dp</dimen>
<dimen name="dp_199">851.2778dp</dimen>
<dimen name="dp_200">855.5556dp</dimen>
<dimen name="dp_201">859.8333dp</dimen>
<dimen name="dp_202">864.1111dp</dimen>
<dimen name="dp_203">868.3889dp</dimen>
<dimen name="dp_204">872.6667dp</dimen>
<dimen name="dp_205">876.9444dp</dimen>
<dimen name="dp_206">881.2222dp</dimen>
<dimen name="dp_207">885.5000dp</dimen>
<dimen name="dp_208">889.7778dp</dimen>
<dimen name="dp_209">894.0556dp</dimen>
<dimen name="dp_210">898.3333dp</dimen>
<dimen name="dp_211">902.6111dp</dimen>
<dimen name="dp_212">906.8889dp</dimen>
<dimen name="dp_213">911.1667dp</dimen>
<dimen name="dp_214">915.4444dp</dimen>
<dimen name="dp_215">919.7222dp</dimen>
<dimen name="dp_216">924.0000dp</dimen>
<dimen name="dp_217">928.2778dp</dimen>
<dimen name="dp_218">932.5556dp</dimen>
<dimen name="dp_219">936.8333dp</dimen>
<dimen name="dp_220">941.1111dp</dimen>
<dimen name="dp_221">945.3889dp</dimen>
<dimen name="dp_222">949.6667dp</dimen>
<dimen name="dp_223">953.9444dp</dimen>
<dimen name="dp_224">958.2222dp</dimen>
<dimen name="dp_225">962.5000dp</dimen>
<dimen name="dp_226">966.7778dp</dimen>
<dimen name="dp_227">971.0556dp</dimen>
<dimen name="dp_228">975.3333dp</dimen>
<dimen name="dp_229">979.6111dp</dimen>
<dimen name="dp_230">983.8889dp</dimen>
<dimen name="dp_231">988.1667dp</dimen>
<dimen name="dp_232">992.4444dp</dimen>
<dimen name="dp_233">996.7222dp</dimen>
<dimen name="dp_234">1001.0000dp</dimen>
<dimen name="dp_235">1005.2778dp</dimen>
<dimen name="dp_236">1009.5556dp</dimen>
<dimen name="dp_237">1013.8333dp</dimen>
<dimen name="dp_238">1018.1111dp</dimen>
<dimen name="dp_239">1022.3889dp</dimen>
<dimen name="dp_240">1026.6667dp</dimen>
<dimen name="dp_241">1030.9444dp</dimen>
<dimen name="dp_242">1035.2222dp</dimen>
<dimen name="dp_243">1039.5000dp</dimen>
<dimen name="dp_244">1043.7778dp</dimen>
<dimen name="dp_245">1048.0556dp</dimen>
<dimen name="dp_246">1052.3333dp</dimen>
<dimen name="dp_247">1056.6111dp</dimen>
<dimen name="dp_248">1060.8889dp</dimen>
<dimen name="dp_249">1065.1667dp</dimen>
<dimen name="dp_250">1069.4444dp</dimen>
<dimen name="dp_251">1073.7222dp</dimen>
<dimen name="dp_252">1078.0000dp</dimen>
<dimen name="dp_253">1082.2778dp</dimen>
<dimen name="dp_254">1086.5556dp</dimen>
<dimen name="dp_255">1090.8333dp</dimen>
<dimen name="dp_256">1095.1111dp</dimen>
<dimen name="dp_257">1099.3889dp</dimen>
<dimen name="dp_258">1103.6667dp</dimen>
<dimen name="dp_259">1107.9444dp</dimen>
<dimen name="dp_260">1112.2222dp</dimen>
<dimen name="dp_261">1116.5000dp</dimen>
<dimen name="dp_262">1120.7778dp</dimen>
<dimen name="dp_263">1125.0556dp</dimen>
<dimen name="dp_264">1129.3333dp</dimen>
<dimen name="dp_265">1133.6111dp</dimen>
<dimen name="dp_266">1137.8889dp</dimen>
<dimen name="dp_267">1142.1667dp</dimen>
<dimen name="dp_268">1146.4444dp</dimen>
<dimen name="dp_269">1150.7222dp</dimen>
<dimen name="dp_270">1155.0000dp</dimen>
<dimen name="dp_271">1159.2778dp</dimen>
<dimen name="dp_272">1163.5556dp</dimen>
<dimen name="dp_273">1167.8333dp</dimen>
<dimen name="dp_274">1172.1111dp</dimen>
<dimen name="dp_275">1176.3889dp</dimen>
<dimen name="dp_276">1180.6667dp</dimen>
<dimen name="dp_277">1184.9444dp</dimen>
<dimen name="dp_278">1189.2222dp</dimen>
<dimen name="dp_279">1193.5000dp</dimen>
<dimen name="dp_280">1197.7778dp</dimen>
<dimen name="dp_281">1202.0556dp</dimen>
<dimen name="dp_282">1206.3333dp</dimen>
<dimen name="dp_283">1210.6111dp</dimen>
<dimen name="dp_284">1214.8889dp</dimen>
<dimen name="dp_285">1219.1667dp</dimen>
<dimen name="dp_286">1223.4444dp</dimen>
<dimen name="dp_287">1227.7222dp</dimen>
<dimen name="dp_288">1232.0000dp</dimen>
<dimen name="dp_289">1236.2778dp</dimen>
<dimen name="dp_290">1240.5556dp</dimen>
<dimen name="dp_291">1244.8333dp</dimen>
<dimen name="dp_292">1249.1111dp</dimen>
<dimen name="dp_293">1253.3889dp</dimen>
<dimen name="dp_294">1257.6667dp</dimen>
<dimen name="dp_295">1261.9444dp</dimen>
<dimen name="dp_296">1266.2222dp</dimen>
<dimen name="dp_297">1270.5000dp</dimen>
<dimen name="dp_298">1274.7778dp</dimen>
<dimen name="dp_299">1279.0556dp</dimen>
<dimen name="dp_300">1283.3333dp</dimen>
<dimen name="dp_301">1287.6111dp</dimen>
<dimen name="dp_302">1291.8889dp</dimen>
<dimen name="dp_303">1296.1667dp</dimen>
<dimen name="dp_304">1300.4444dp</dimen>
<dimen name="dp_305">1304.7222dp</dimen>
<dimen name="dp_306">1309.0000dp</dimen>
<dimen name="dp_307">1313.2778dp</dimen>
<dimen name="dp_308">1317.5556dp</dimen>
<dimen name="dp_309">1321.8333dp</dimen>
<dimen name="dp_310">1326.1111dp</dimen>
<dimen name="dp_311">1330.3889dp</dimen>
<dimen name="dp_312">1334.6667dp</dimen>
<dimen name="dp_313">1338.9444dp</dimen>
<dimen name="dp_314">1343.2222dp</dimen>
<dimen name="dp_315">1347.5000dp</dimen>
<dimen name="dp_316">1351.7778dp</dimen>
<dimen name="dp_317">1356.0556dp</dimen>
<dimen name="dp_318">1360.3333dp</dimen>
<dimen name="dp_319">1364.6111dp</dimen>
<dimen name="dp_320">1368.8889dp</dimen>
<dimen name="dp_321">1373.1667dp</dimen>
<dimen name="dp_322">1377.4444dp</dimen>
<dimen name="dp_323">1381.7222dp</dimen>
<dimen name="dp_324">1386.0000dp</dimen>
<dimen name="dp_325">1390.2778dp</dimen>
<dimen name="dp_326">1394.5556dp</dimen>
<dimen name="dp_327">1398.8333dp</dimen>
<dimen name="dp_328">1403.1111dp</dimen>
<dimen name="dp_329">1407.3889dp</dimen>
<dimen name="dp_330">1411.6667dp</dimen>
<dimen name="dp_331">1415.9444dp</dimen>
<dimen name="dp_332">1420.2222dp</dimen>
<dimen name="dp_333">1424.5000dp</dimen>
<dimen name="dp_334">1428.7778dp</dimen>
<dimen name="dp_335">1433.0556dp</dimen>
<dimen name="dp_336">1437.3333dp</dimen>
<dimen name="dp_337">1441.6111dp</dimen>
<dimen name="dp_338">1445.8889dp</dimen>
<dimen name="dp_339">1450.1667dp</dimen>
<dimen name="dp_340">1454.4444dp</dimen>
<dimen name="dp_341">1458.7222dp</dimen>
<dimen name="dp_342">1463.0000dp</dimen>
<dimen name="dp_343">1467.2778dp</dimen>
<dimen name="dp_344">1471.5556dp</dimen>
<dimen name="dp_345">1475.8333dp</dimen>
<dimen name="dp_346">1480.1111dp</dimen>
<dimen name="dp_347">1484.3889dp</dimen>
<dimen name="dp_348">1488.6667dp</dimen>
<dimen name="dp_349">1492.9444dp</dimen>
<dimen name="dp_350">1497.2222dp</dimen>
<dimen name="dp_351">1501.5000dp</dimen>
<dimen name="dp_352">1505.7778dp</dimen>
<dimen name="dp_353">1510.0556dp</dimen>
<dimen name="dp_354">1514.3333dp</dimen>
<dimen name="dp_355">1518.6111dp</dimen>
<dimen name="dp_356">1522.8889dp</dimen>
<dimen name="dp_357">1527.1667dp</dimen>
<dimen name="dp_358">1531.4444dp</dimen>
<dimen name="dp_359">1535.7222dp</dimen>
<dimen name="dp_360">1540.0000dp</dimen>
<dimen name="dp_365">1561.3889dp</dimen>
<dimen name="dp_370">1582.7778dp</dimen>
<dimen name="dp_380">1625.5556dp</dimen>
<dimen name="dp_385">1646.9444dp</dimen>
<dimen name="dp_400">1711.1111dp</dimen>
<dimen name="dp_410">1753.8889dp</dimen>
<dimen name="dp_422">1805.2222dp</dimen>
<dimen name="dp_472">2019.1111dp</dimen>
<dimen name="dp_500">2138.8889dp</dimen>
<dimen name="dp_600">2566.6667dp</dimen>
<dimen name="dp_640">2737.7778dp</dimen>
<dimen name="dp_720">3080.0000dp</dimen>
<dimen name="sp_6">25.6667dp</dimen>
<dimen name="sp_7">29.9444dp</dimen>
<dimen name="sp_8">34.2222dp</dimen>
<dimen name="sp_9">38.5000dp</dimen>
<dimen name="sp_10">42.7778dp</dimen>
<dimen name="sp_11">47.0556dp</dimen>
<dimen name="sp_12">51.3333dp</dimen>
<dimen name="sp_13">55.6111dp</dimen>
<dimen name="sp_14">59.8889dp</dimen>
<dimen name="sp_15">64.1667dp</dimen>
<dimen name="sp_16">68.4444dp</dimen>
<dimen name="sp_17">72.7222dp</dimen>
<dimen name="sp_18">77.0000dp</dimen>
<dimen name="sp_19">81.2778dp</dimen>
<dimen name="sp_20">85.5556dp</dimen>
<dimen name="sp_21">89.8333dp</dimen>
<dimen name="sp_22">94.1111dp</dimen>
<dimen name="sp_23">98.3889dp</dimen>
<dimen name="sp_24">102.6667dp</dimen>
<dimen name="sp_25">106.9444dp</dimen>
<dimen name="sp_28">119.7778dp</dimen>
<dimen name="sp_30">128.3333dp</dimen>
<dimen name="sp_32">136.8889dp</dimen>
<dimen name="sp_34">145.4444dp</dimen>
<dimen name="sp_36">154.0000dp</dimen>
<dimen name="sp_38">162.5556dp</dimen>
<dimen name="sp_40">171.1111dp</dimen>
<dimen name="sp_42">179.6667dp</dimen>
<dimen name="sp_48">205.3333dp</dimen>
<dimen name="sp_58">248.1111dp</dimen>
<dimen name="sp_115">491.9444dp</dimen>
</resources>
+2 -2
View File
@@ -1,8 +1,8 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
apply from: "compile.gradle" apply from: "compile.gradle"
buildscript { buildscript {
// ext.kotlin_version = "1.5.0" ext.kotlin_version = "1.5.0"
ext.kotlin_version = "1.6.10" // ext.kotlin_version = "1.6.10"
repositories { repositories {
google() google()
jcenter() // 这个 jcenter() // 这个
+1 -1
View File
@@ -66,7 +66,7 @@ dependencies {
api rootProject.ext.dependencies["Xpopup"] api rootProject.ext.dependencies["Xpopup"]
api rootProject.ext.dependencies["Countdownview"] api rootProject.ext.dependencies["Countdownview"]
// api rootProject.ext.dependencies["CheckVersionLib"] // api rootProject.ext.dependencies["CheckVersionLib"]
api rootProject.ext.dependencies["Bugly"] // api rootProject.ext.dependencies["Bugly"]
// api rootProject.ext.dependencies["Zxing"] // api rootProject.ext.dependencies["Zxing"]
api rootProject.ext.dependencies["Multidex"] api rootProject.ext.dependencies["Multidex"]
// api rootProject.ext.dependencies["FlycoTabLayout"] // api rootProject.ext.dependencies["FlycoTabLayout"]
@@ -176,7 +176,7 @@ public final class TimeUtil {
* 注意:SimpleDateFormat不是线程安全的,线程安全需用{@code ThreadLocal<SimpleDateFormat>} * 注意:SimpleDateFormat不是线程安全的,线程安全需用{@code ThreadLocal<SimpleDateFormat>}
*/ */
public static final DateFormat DEFAULT_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); private static final DateFormat DEFAULT_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
private static final DateFormat DEFAULT_FORMAT2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZSS:SS", Locale.getDefault()); private static final DateFormat DEFAULT_FORMAT2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZSS:SS", Locale.getDefault());
private static final DateFormat DEFAULT_FORMAT3 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault()); private static final DateFormat DEFAULT_FORMAT3 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());
public static final DateFormat DEFAULT_FORMAT4 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault()); public static final DateFormat DEFAULT_FORMAT4 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());
+1
View File
@@ -0,0 +1 @@
/build
+34
View File
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
apply plugin: 'com.android.library'
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:27.1.1'
testCompile 'junit:junit:4.12'
compile files('libs/license.jar')
}
Binary file not shown.
+18
View File
@@ -0,0 +1,18 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/baidu/IDE/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-dontwarn com.baidu.ocr.**
+32
View File
@@ -0,0 +1,32 @@
<!--
~ Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.baidu.ocr.ui">
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera2.full" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:vmSafeMode="true"
tools:replace="android:allowBackup,android:icon">
<activity
android:name="com.baidu.ocr.ui.camera.CameraActivity"
android:configChanges="screenSize|orientation"
android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" />
</application>
</manifest>
@@ -0,0 +1,128 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.idcardquality;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import com.baidu.idl.authority.AlgorithmOnMainThreadException;
import com.baidu.idl.authority.IDLAuthorityException;
import com.baidu.idl.license.License;
import com.baidu.idl.util.UIThread;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class IDcardQualityProcess {
final ReentrantReadWriteLock nativeModelLock = new ReentrantReadWriteLock();
private static IDcardQualityProcess mInstance;
private static String tokenString;
private static int mAuthorityStatus;
private static Throwable loadNativeException = null;
private static volatile boolean hasReleased;
public IDcardQualityProcess() {
}
public static synchronized IDcardQualityProcess getInstance() {
if (null == mInstance) {
mInstance = new IDcardQualityProcess();
}
return mInstance;
}
public native byte[] convertRGBImage(int[] colors, int width, int height);
public native int idcardQualityModelInit(AssetManager var1, String var2);
public native int idcardQualityCaptchaRelease();
public native int idcardQualityProcess(byte[] var1, int var2, int var3, boolean var4, int var5);
public static synchronized int init(String token) throws AlgorithmOnMainThreadException, IDLAuthorityException {
if (UIThread.isUITread()) {
throw new AlgorithmOnMainThreadException();
} else {
tokenString = token;
try {
mAuthorityStatus = License.getInstance().init(tokenString);
} catch (Exception var2) {
var2.printStackTrace();
}
return mAuthorityStatus;
}
}
public int idcardQualityInit(AssetManager assetManager, String modelPath) {
if (mAuthorityStatus == 0) {
hasReleased = false;
nativeModelLock.writeLock().lock();
int status = this.idcardQualityModelInit(assetManager, modelPath);
nativeModelLock.writeLock().unlock();
return status;
} else {
return mAuthorityStatus;
}
}
public int idcardQualityRelease() {
if (mAuthorityStatus == 0) {
hasReleased = true;
nativeModelLock.writeLock().lock();
this.idcardQualityCaptchaRelease();
nativeModelLock.writeLock().unlock();
return 0;
} else {
return mAuthorityStatus;
}
}
public int idcardQualityDetectionImg(Bitmap img, boolean isfont) {
int status;
if (mAuthorityStatus == 0) {
if (hasReleased) {
return -1;
}
int imgHeight = img.getHeight();
int imgWidth = img.getWidth();
byte[] imageData = this.getRGBImageData(img);
nativeModelLock.readLock().lock();
status = this.idcardQualityProcess(imageData, imgHeight, imgWidth, isfont, 3);
nativeModelLock.readLock().unlock();
return status;
} else {
return mAuthorityStatus;
}
}
public static Throwable getLoadSoException() {
return loadNativeException;
}
public byte[] getRGBImageData(Bitmap img) {
int imgWidth = img.getWidth();
int imgHeight = img.getHeight();
int[] pixels = new int[imgWidth * imgHeight];
img.getPixels(pixels, 0, imgWidth, 0, 0, imgWidth, imgHeight);
byte[] imageData = convertRGBImage(pixels, imgWidth, imgHeight);
return imageData;
}
public void releaseModel() {
this.idcardQualityRelease();
}
static {
try {
System.loadLibrary("idl_license");
System.loadLibrary("idcard_quality.1.1.1");
} catch (Throwable e) {
loadNativeException = e;
}
mInstance = null;
mAuthorityStatus = 256;
}
}
@@ -0,0 +1,573 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.camera;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.view.TextureView;
import android.view.View;
import android.widget.FrameLayout;
import androidx.core.app.ActivityCompat;
/**
* 5.0以下相机API的封装。
*/
@SuppressWarnings("deprecation")
public class Camera1Control implements ICameraControl {
private int displayOrientation = 0;
private int cameraId = 0;
private int flashMode;
private AtomicBoolean takingPicture = new AtomicBoolean(false);
private AtomicBoolean abortingScan = new AtomicBoolean(false);
private Context context;
private Camera camera;
private Camera.Parameters parameters;
private PermissionCallback permissionCallback;
private Rect previewFrame = new Rect();
private PreviewView previewView;
private View displayView;
private int rotation = 0;
private OnDetectPictureCallback detectCallback;
private int previewFrameCount = 0;
private Camera.Size optSize;
/*
* 非扫描模式
*/
private final int MODEL_NOSCAN = 0;
/*
* 本地质量控制扫描模式
*/
private final int MODEL_SCAN = 1;
private int detectType = MODEL_NOSCAN;
public int getCameraRotation() {
return rotation;
}
public AtomicBoolean getAbortingScan() {
return abortingScan;
}
@Override
public void setDetectCallback(OnDetectPictureCallback callback) {
detectType = MODEL_SCAN;
detectCallback = callback;
}
private void onRequestDetect(byte[] data) {
// 相机已经关闭
if (camera == null || data == null || optSize == null) {
return;
}
YuvImage img = new YuvImage(data, ImageFormat.NV21, optSize.width, optSize.height, null);
ByteArrayOutputStream os = null;
try {
os = new ByteArrayOutputStream(data.length);
img.compressToJpeg(new Rect(0, 0, optSize.width, optSize.height), 80, os);
byte[] jpeg = os.toByteArray();
int status = detectCallback.onDetect(jpeg, getCameraRotation());
if (status == 0) {
clearPreviewCallback();
}
} catch (OutOfMemoryError e) {
// 内存溢出则取消当次操作
} finally {
try {
os.close();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
@Override
public void setDisplayOrientation(@CameraView.Orientation int displayOrientation) {
this.displayOrientation = displayOrientation;
switch (displayOrientation) {
case CameraView.ORIENTATION_PORTRAIT:
rotation = 90;
break;
case CameraView.ORIENTATION_HORIZONTAL:
rotation = 0;
break;
case CameraView.ORIENTATION_INVERT:
rotation = 180;
break;
default:
rotation = 0;
}
previewView.requestLayout();
}
/**
* {@inheritDoc}
*/
@Override
public void refreshPermission() {
startPreview(true);
}
/**
* {@inheritDoc}
*/
@Override
public void setFlashMode(@FlashMode int flashMode) {
if (this.flashMode == flashMode) {
return;
}
this.flashMode = flashMode;
updateFlashMode(flashMode);
}
@Override
public int getFlashMode() {
return flashMode;
}
@Override
public void start() {
startPreview(false);
}
@Override
public void stop() {
if (camera != null) {
camera.setPreviewCallback(null);
stopPreview();
// 避免同步代码,为了先设置null后release
Camera tempC = camera;
camera = null;
tempC.release();
camera = null;
buffer = null;
}
}
private void stopPreview() {
if (camera != null) {
camera.stopPreview();
}
}
@Override
public void pause() {
if (camera != null) {
stopPreview();
}
setFlashMode(FLASH_MODE_OFF);
}
@Override
public void resume() {
takingPicture.set(false);
if (camera == null) {
openCamera();
} else {
previewView.textureView.setSurfaceTextureListener(surfaceTextureListener);
if (previewView.textureView.isAvailable()) {
startPreview(false);
}
}
}
@Override
public View getDisplayView() {
return displayView;
}
@Override
public void takePicture(final OnTakePictureCallback onTakePictureCallback) {
if (takingPicture.get()) {
return;
}
switch (displayOrientation) {
case CameraView.ORIENTATION_PORTRAIT:
parameters.setRotation(90);
break;
case CameraView.ORIENTATION_HORIZONTAL:
parameters.setRotation(0);
break;
case CameraView.ORIENTATION_INVERT:
parameters.setRotation(180);
break;
}
try {
Camera.Size picSize = getOptimalSize(camera.getParameters().getSupportedPictureSizes());
parameters.setPictureSize(picSize.width, picSize.height);
camera.setParameters(parameters);
takingPicture.set(true);
cancelAutoFocus();
CameraThreadPool.execute(new Runnable() {
@Override
public void run() {
camera.takePicture(null, null, new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
startPreview(false);
takingPicture.set(false);
if (onTakePictureCallback != null) {
onTakePictureCallback.onPictureTaken(data);
}
}
});
}
});
} catch (RuntimeException e) {
e.printStackTrace();
startPreview(false);;
takingPicture.set(false);
}
}
@Override
public void setPermissionCallback(PermissionCallback callback) {
this.permissionCallback = callback;
}
public Camera1Control(Context context) {
this.context = context;
previewView = new PreviewView(context);
openCamera();
}
private void openCamera() {
setupDisplayView();
}
private void setupDisplayView() {
final TextureView textureView = new TextureView(context);
previewView.textureView = textureView;
previewView.setTextureView(textureView);
displayView = previewView;
textureView.setSurfaceTextureListener(surfaceTextureListener);
}
private SurfaceTexture surfaceCache;
private byte[] buffer = null;
private void setPreviewCallbackImpl() {
if (buffer == null) {
buffer = new byte[displayView.getWidth()
* displayView.getHeight() * ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8];
}
if (camera != null && detectType == MODEL_SCAN) {
camera.addCallbackBuffer(buffer);
camera.setPreviewCallback(previewCallback);
}
}
private void clearPreviewCallback() {
if (camera != null && detectType == MODEL_SCAN) {
camera.setPreviewCallback(null);
stopPreview();
}
}
Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(final byte[] data, Camera camera) {
// 扫描成功阻止打开新线程处理
if (abortingScan.get()) {
return;
}
// 节流
if (previewFrameCount++ % 5 != 0) {
return;
}
// 在某些机型和某项项目中,某些帧的data的数据不符合nv21的格式,需要过滤,否则后续处理会导致crash
if (data.length != parameters.getPreviewSize().width * parameters.getPreviewSize().height * 1.5) {
return;
}
camera.addCallbackBuffer(buffer);
CameraThreadPool.execute(new Runnable() {
@Override
public void run() {
Camera1Control.this.onRequestDetect(data);
}
});
}
};
private void initCamera() {
try {
if (camera == null) {
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
cameraId = i;
}
}
try {
camera = Camera.open(cameraId);
} catch (Throwable e) {
e.printStackTrace();
startPreview(true);
return;
}
}
if (parameters == null) {
parameters = camera.getParameters();
parameters.setPreviewFormat(ImageFormat.NV21);
}
opPreviewSize(previewView.getWidth(), previewView.getHeight());
camera.setPreviewTexture(surfaceCache);
setPreviewCallbackImpl();
startPreview(false);
} catch (IOException e) {
e.printStackTrace();
}
}
private TextureView.SurfaceTextureListener surfaceTextureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
surfaceCache = surface;
initCamera();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
opPreviewSize(previewView.getWidth(), previewView.getHeight());
startPreview(false);
setPreviewCallbackImpl();
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
setPreviewCallbackImpl();
}
};
// 开启预览
private void startPreview(boolean checkPermission) {
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
if (checkPermission && permissionCallback != null) {
permissionCallback.onRequestPermission();
}
return;
}
if (camera == null) {
initCamera();
} else {
camera.startPreview();
startAutoFocus();
}
}
private void cancelAutoFocus() {
camera.cancelAutoFocus();
CameraThreadPool.cancelAutoFocusTimer();
}
private void startAutoFocus() {
CameraThreadPool.createAutoFocusTimerTask(new Runnable() {
@Override
public void run() {
synchronized (Camera1Control.this) {
if (camera != null && !takingPicture.get()) {
try {
camera.autoFocus(new Camera.AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
}
});
} catch (Throwable e) {
// startPreview是异步实现,可能在某些机器上前几次调用会autofocus failß
}
}
}
}
});
}
private void opPreviewSize(int width, @SuppressWarnings("unused") int height) {
if (parameters != null && camera != null && width > 0) {
optSize = getOptimalSize(camera.getParameters().getSupportedPreviewSizes());
parameters.setPreviewSize(optSize.width, optSize.height);
previewView.setRatio(1.0f * optSize.width / optSize.height);
camera.setDisplayOrientation(getSurfaceOrientation());
stopPreview();
try {
camera.setParameters(parameters);
} catch (RuntimeException e) {
e.printStackTrace();
}
}
}
private Camera.Size getOptimalSize(List<Camera.Size> sizes) {
int width = previewView.textureView.getWidth();
int height = previewView.textureView.getHeight();
Camera.Size pictureSize = sizes.get(0);
List<Camera.Size> candidates = new ArrayList<>();
for (Camera.Size size : sizes) {
if (size.width >= width && size.height >= height && size.width * height == size.height * width) {
// 比例相同
candidates.add(size);
} else if (size.height >= width && size.width >= height && size.width * width == size.height * height) {
// 反比例
candidates.add(size);
}
}
if (!candidates.isEmpty()) {
return Collections.min(candidates, sizeComparator);
}
for (Camera.Size size : sizes) {
if (size.width > width && size.height > height) {
return size;
}
}
return pictureSize;
}
private Comparator<Camera.Size> sizeComparator = new Comparator<Camera.Size>() {
@Override
public int compare(Camera.Size lhs, Camera.Size rhs) {
return Long.signum((long) lhs.width * lhs.height - (long) rhs.width * rhs.height);
}
};
private void updateFlashMode(int flashMode) {
switch (flashMode) {
case FLASH_MODE_TORCH:
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
break;
case FLASH_MODE_OFF:
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
break;
case ICameraControl.FLASH_MODE_AUTO:
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
break;
default:
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
break;
}
camera.setParameters(parameters);
}
private int getSurfaceOrientation() {
@CameraView.Orientation
int orientation = displayOrientation;
switch (orientation) {
case CameraView.ORIENTATION_PORTRAIT:
return 90;
case CameraView.ORIENTATION_HORIZONTAL:
return 0;
case CameraView.ORIENTATION_INVERT:
return 180;
default:
return 90;
}
}
/**
* 有些相机匹配不到完美的比例。比如。我们的layout是4:3的。预览只有16:9
* 的,如果直接显示图片会拉伸,变形。缩放的话,又有黑边。所以我们采取的策略
* 是,等比例放大。这样预览的有一部分会超出屏幕。拍照后再进行裁剪处理。
*/
private class PreviewView extends FrameLayout {
private TextureView textureView;
private float ratio = 0.75f;
void setTextureView(TextureView textureView) {
this.textureView = textureView;
removeAllViews();
addView(textureView);
}
void setRatio(float ratio) {
this.ratio = ratio;
requestLayout();
relayout(getWidth(), getHeight());
}
public PreviewView(Context context) {
super(context);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
relayout(w, h);
}
private void relayout(int w, int h) {
int width = w;
int height = h;
if (w < h) {
// 垂直模式,高度固定。
height = (int) (width * ratio);
} else {
// 水平模式,宽度固定。
width = (int) (height * ratio);
}
int l = (getWidth() - width) / 2;
int t = (getHeight() - height) / 2;
previewFrame.left = l;
previewFrame.top = t;
previewFrame.right = l + width;
previewFrame.bottom = t + height;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
textureView.layout(previewFrame.left, previewFrame.top, previewFrame.right, previewFrame.bottom);
}
}
@Override
public Rect getPreviewFrame() {
return previewFrame;
}
}
@@ -0,0 +1,697 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.camera;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import android.Manifest;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class Camera2Control implements ICameraControl {
@Override
public void setDetectCallback(OnDetectPictureCallback callback) {
// TODO 暂时只用camera
}
@Override
public AtomicBoolean getAbortingScan() {
// TODO 暂时只用camera
return null;
}
/**
* Conversion from screen rotation to JPEG orientation.
*/
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private static final int MAX_PREVIEW_SIZE = 2048;
static {
ORIENTATIONS.append(Surface.ROTATION_0, 90);
ORIENTATIONS.append(Surface.ROTATION_90, 0);
ORIENTATIONS.append(Surface.ROTATION_180, 270);
ORIENTATIONS.append(Surface.ROTATION_270, 180);
}
private static final int STATE_PREVIEW = 0;
private static final int STATE_WAITING_FOR_LOCK = 1;
private static final int STATE_WAITING_FOR_CAPTURE = 2;
private static final int STATE_CAPTURING = 3;
private static final int STATE_PICTURE_TAKEN = 4;
private static final int MAX_PREVIEW_WIDTH = 1920;
private static final int MAX_PREVIEW_HEIGHT = 1080;
private int flashMode;
private int orientation = 0;
private int state = STATE_PREVIEW;
private Context context;
private OnTakePictureCallback onTakePictureCallback;
private PermissionCallback permissionCallback;
private String cameraId;
private TextureView textureView;
private Size previewSize;
private Rect previewFrame = new Rect();
private HandlerThread backgroundThread;
private Handler backgroundHandler;
private ImageReader imageReader;
private CameraCaptureSession captureSession;
private CameraDevice cameraDevice;
private CaptureRequest.Builder previewRequestBuilder;
private CaptureRequest previewRequest;
private Semaphore cameraLock = new Semaphore(1);
private int sensorOrientation;
@Override
public void start() {
startBackgroundThread();
if (textureView.isAvailable()) {
openCamera(textureView.getWidth(), textureView.getHeight());
textureView.setSurfaceTextureListener(surfaceTextureListener);
} else {
textureView.setSurfaceTextureListener(surfaceTextureListener);
}
}
@Override
public void stop() {
textureView.setSurfaceTextureListener(null);
closeCamera();
stopBackgroundThread();
}
@Override
public void pause() {
setFlashMode(FLASH_MODE_OFF);
}
@Override
public void resume() {
state = STATE_PREVIEW;
}
@Override
public View getDisplayView() {
return textureView;
}
@Override
public Rect getPreviewFrame() {
return previewFrame;
}
@Override
public void takePicture(OnTakePictureCallback callback) {
this.onTakePictureCallback = callback;
// 拍照第一步,对焦
lockFocus();
}
@Override
public void setPermissionCallback(PermissionCallback callback) {
this.permissionCallback = callback;
}
@Override
public void setDisplayOrientation(@CameraView.Orientation int displayOrientation) {
this.orientation = displayOrientation / 90;
}
@Override
public void refreshPermission() {
openCamera(textureView.getWidth(), textureView.getHeight());
}
@Override
public void setFlashMode(@FlashMode int flashMode) {
if (this.flashMode == flashMode) {
return;
}
this.flashMode = flashMode;
try {
previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
updateFlashMode(flashMode, previewRequestBuilder);
previewRequest = previewRequestBuilder.build();
captureSession.setRepeatingRequest(previewRequest, captureCallback, backgroundHandler);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public int getFlashMode() {
return flashMode;
}
public Camera2Control(Context activity) {
this.context = activity;
textureView = new TextureView(activity);
}
private final TextureView.SurfaceTextureListener surfaceTextureListener =
new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
openCamera(width, height);
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
configureTransform(width, height);
previewFrame.left = 0;
previewFrame.top = 0;
previewFrame.right = width;
previewFrame.bottom = height;
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
stop();
return true;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture texture) {
}
};
private void openCamera(int width, int height) {
// 6.0+的系统需要检查系统权限 。
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
requestCameraPermission();
return;
}
setUpCameraOutputs(width, height);
configureTransform(width, height);
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
try {
if (!cameraLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
throw new RuntimeException("Time out waiting to lock camera opening.");
}
manager.openCamera(cameraId, deviceStateCallback, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
}
}
private final CameraDevice.StateCallback deviceStateCallback = new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
cameraLock.release();
Camera2Control.this.cameraDevice = cameraDevice;
createCameraPreviewSession();
}
@Override
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
cameraLock.release();
cameraDevice.close();
Camera2Control.this.cameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int error) {
cameraLock.release();
cameraDevice.close();
Camera2Control.this.cameraDevice = null;
}
};
private void createCameraPreviewSession() {
try {
SurfaceTexture texture = textureView.getSurfaceTexture();
assert texture != null;
texture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
Surface surface = new Surface(texture);
previewRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
previewRequestBuilder.addTarget(surface);
updateFlashMode(this.flashMode, previewRequestBuilder);
cameraDevice.createCaptureSession(Arrays.asList(surface, imageReader.getSurface()),
new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
// The camera is already closed
if (null == cameraDevice) {
return;
}
captureSession = cameraCaptureSession;
try {
previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
previewRequest = previewRequestBuilder.build();
captureSession.setRepeatingRequest(previewRequest,
captureCallback, backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
@Override
public void onConfigureFailed(
@NonNull CameraCaptureSession cameraCaptureSession) {
// TODO
}
}, null
);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private final ImageReader.OnImageAvailableListener onImageAvailableListener =
new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader reader) {
if (onTakePictureCallback != null) {
Image image = reader.acquireNextImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
image.close();
onTakePictureCallback.onPictureTaken(bytes);
}
}
};
private CameraCaptureSession.CaptureCallback captureCallback =
new CameraCaptureSession.CaptureCallback() {
private void process(CaptureResult result) {
switch (state) {
case STATE_PREVIEW: {
break;
}
case STATE_WAITING_FOR_LOCK: {
Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
if (afState == null) {
captureStillPicture();
return;
}
switch (afState) {
case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED:
case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED:
case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED: {
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null
|| aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
captureStillPicture();
} else {
runPreCaptureSequence();
}
break;
}
default:
captureStillPicture();
}
break;
}
case STATE_WAITING_FOR_CAPTURE: {
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null
|| aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE
|| aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
state = STATE_CAPTURING;
} else {
if (aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
captureStillPicture();
}
}
break;
}
case STATE_CAPTURING: {
Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
captureStillPicture();
}
break;
}
default:
break;
}
}
@Override
public void onCaptureProgressed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull CaptureResult partialResult) {
process(partialResult);
}
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
process(result);
}
};
private Size getOptimalSize(Size[] choices, int textureViewWidth,
int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {
List<Size> bigEnough = new ArrayList<>();
List<Size> notBigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight
&& option.getHeight() == option.getWidth() * h / w) {
if (option.getWidth() >= textureViewWidth
&& option.getHeight() >= textureViewHeight) {
bigEnough.add(option);
} else {
notBigEnough.add(option);
}
}
}
// Pick the smallest of those big enough. If there is no one big enough, pick the
// largest of those not big enough.
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, sizeComparator);
}
for (Size option : choices) {
if (option.getWidth() >= maxWidth && option.getHeight() >= maxHeight) {
return option;
}
}
if (notBigEnough.size() > 0) {
return Collections.max(notBigEnough, sizeComparator);
}
return choices[0];
}
private Comparator<Size> sizeComparator = new Comparator<Size>() {
@Override
public int compare(Size lhs, Size rhs) {
return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
}
};
private void requestCameraPermission() {
if (permissionCallback != null) {
permissionCallback.onRequestPermission();
}
}
@SuppressWarnings("SuspiciousNameCombination")
private void setUpCameraOutputs(int width, int height) {
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
try {
for (String cameraId : manager.getCameraIdList()) {
CameraCharacteristics characteristics =
manager.getCameraCharacteristics(cameraId);
Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
continue;
}
StreamConfigurationMap map = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
continue;
}
// int preferredPictureSize = (int) (Math.max(textureView.getWidth(), textureView
// .getHeight()) * 1.5);
// preferredPictureSize = Math.min(preferredPictureSize, 2560);
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Point screenSize = new Point();
windowManager.getDefaultDisplay().getSize(screenSize);
int maxImageSize = Math.max(MAX_PREVIEW_SIZE, screenSize.y * 3 / 2);
Size size = getOptimalSize(map.getOutputSizes(ImageFormat.JPEG), textureView.getWidth(),
textureView.getHeight(), maxImageSize, maxImageSize, new Size(4, 3));
imageReader = ImageReader.newInstance(size.getWidth(), size.getHeight(),
ImageFormat.JPEG, 1);
imageReader.setOnImageAvailableListener(
onImageAvailableListener, backgroundHandler);
int displayRotation = orientation;
// noinspection ConstantConditions
sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
boolean swappedDimensions = false;
switch (displayRotation) {
case Surface.ROTATION_0:
case Surface.ROTATION_180:
if (sensorOrientation == 90 || sensorOrientation == 270) {
swappedDimensions = true;
}
break;
case Surface.ROTATION_90:
case Surface.ROTATION_270:
if (sensorOrientation == 0 || sensorOrientation == 180) {
swappedDimensions = true;
}
break;
default:
}
int rotatedPreviewWidth = width;
int rotatedPreviewHeight = height;
int maxPreviewWidth = screenSize.x;
int maxPreviewHeight = screenSize.y;
if (swappedDimensions) {
rotatedPreviewWidth = height;
rotatedPreviewHeight = width;
maxPreviewWidth = screenSize.y;
maxPreviewHeight = screenSize.x;
}
maxPreviewWidth = Math.min(maxPreviewWidth, MAX_PREVIEW_WIDTH);
maxPreviewHeight = Math.min(maxPreviewHeight, MAX_PREVIEW_HEIGHT);
previewSize = getOptimalSize(map.getOutputSizes(SurfaceTexture.class),
rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
maxPreviewHeight, size);
this.cameraId = cameraId;
return;
}
} catch (CameraAccessException | NullPointerException e) {
e.printStackTrace();
}
}
private void closeCamera() {
try {
cameraLock.acquire();
if (null != captureSession) {
captureSession.close();
captureSession = null;
}
if (null != cameraDevice) {
cameraDevice.close();
cameraDevice = null;
}
if (null != imageReader) {
imageReader.close();
imageReader = null;
}
} catch (InterruptedException e) {
throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
} finally {
cameraLock.release();
}
}
private void startBackgroundThread() {
backgroundThread = new HandlerThread("ocr_camera");
backgroundThread.start();
backgroundHandler = new Handler(backgroundThread.getLooper());
}
private void stopBackgroundThread() {
if (backgroundThread != null) {
backgroundThread.quitSafely();
backgroundThread = null;
backgroundHandler = null;
}
}
private void configureTransform(int viewWidth, int viewHeight) {
if (null == textureView || null == previewSize || null == context) {
return;
}
int rotation = orientation;
Matrix matrix = new Matrix();
RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
RectF bufferRect = new RectF(0, 0, previewSize.getHeight(), previewSize.getWidth());
float centerX = viewRect.centerX();
float centerY = viewRect.centerY();
if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
float scale = Math.max(
(float) viewHeight / previewSize.getHeight(),
(float) viewWidth / previewSize.getWidth());
matrix.postScale(scale, scale, centerX, centerY);
matrix.postRotate(90 * (rotation - 2), centerX, centerY);
} else if (Surface.ROTATION_180 == rotation) {
matrix.postRotate(180, centerX, centerY);
}
textureView.setTransform(matrix);
}
// 拍照前,先对焦
private void lockFocus() {
if (captureSession != null && state == STATE_PREVIEW) {
try {
previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_START);
state = STATE_WAITING_FOR_LOCK;
captureSession.capture(previewRequestBuilder.build(), captureCallback,
backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
}
private void runPreCaptureSequence() {
try {
previewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
state = STATE_WAITING_FOR_CAPTURE;
captureSession.capture(previewRequestBuilder.build(), captureCallback,
backgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
// 拍照session
private void captureStillPicture() {
try {
if (null == context || null == cameraDevice) {
return;
}
final CaptureRequest.Builder captureBuilder =
cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
captureBuilder.addTarget(imageReader.getSurface());
captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(orientation));
updateFlashMode(this.flashMode, captureBuilder);
CameraCaptureSession.CaptureCallback captureCallback =
new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
unlockFocus();
}
@Override
public void onCaptureFailed(@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull CaptureFailure failure) {
super.onCaptureFailed(session, request, failure);
}
};
// 停止预览
captureSession.stopRepeating();
captureSession.capture(captureBuilder.build(), captureCallback, backgroundHandler);
state = STATE_PICTURE_TAKEN;
// unlockFocus();
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private int getOrientation(int rotation) {
return (ORIENTATIONS.get(rotation) + sensorOrientation + 270) % 360;
}
// 停止对焦
private void unlockFocus() {
try {
previewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
captureSession.capture(previewRequestBuilder.build(), captureCallback,
backgroundHandler);
state = STATE_PREVIEW;
// 预览
captureSession.setRepeatingRequest(previewRequest, captureCallback,
backgroundHandler);
textureView.setSurfaceTextureListener(surfaceTextureListener);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}
private void updateFlashMode(@FlashMode int flashMode, CaptureRequest.Builder builder) {
switch (flashMode) {
case FLASH_MODE_TORCH:
builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_TORCH);
break;
case FLASH_MODE_OFF:
builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_OFF);
break;
case ICameraControl.FLASH_MODE_AUTO:
default:
builder.set(CaptureRequest.FLASH_MODE, CameraMetadata.FLASH_MODE_SINGLE);
break;
}
}
}
@@ -0,0 +1,516 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.camera;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import com.baidu.idcardquality.IDcardQualityProcess;
import com.baidu.ocr.ui.R;
import com.baidu.ocr.ui.crop.CropView;
import com.baidu.ocr.ui.crop.FrameOverlayView;
import android.Manifest;
import android.app.Activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.provider.MediaStore;
import android.view.Surface;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
public class CameraActivity extends Activity {
public static final String KEY_OUTPUT_FILE_PATH = "outputFilePath";
public static final String KEY_CONTENT_TYPE = "contentType";
public static final String KEY_NATIVE_TOKEN = "nativeToken";
public static final String KEY_NATIVE_ENABLE = "nativeEnable";
public static final String KEY_NATIVE_MANUAL = "nativeEnableManual";
public static final String CONTENT_TYPE_GENERAL = "general";
public static final String CONTENT_TYPE_ID_CARD_FRONT = "IDCardFront";
public static final String CONTENT_TYPE_ID_CARD_BACK = "IDCardBack";
public static final String CONTENT_TYPE_BANK_CARD = "bankCard";
public static final String CONTENT_TYPE_PASSPORT = "passport";
private static final int REQUEST_CODE_PICK_IMAGE = 100;
private static final int PERMISSIONS_REQUEST_CAMERA = 800;
private static final int PERMISSIONS_EXTERNAL_STORAGE = 801;
private File outputFile;
private String contentType;
private Handler handler = new Handler();
private boolean isNativeEnable;
private boolean isNativeManual;
private OCRCameraLayout takePictureContainer;
private OCRCameraLayout cropContainer;
private OCRCameraLayout confirmResultContainer;
private ImageView lightButton;
private CameraView cameraView;
private ImageView displayImageView;
private CropView cropView;
private FrameOverlayView overlayView;
private MaskView cropMaskView;
private ImageView takePhotoBtn;
private PermissionCallback permissionCallback = new PermissionCallback() {
@Override
public boolean onRequestPermission() {
ActivityCompat.requestPermissions(CameraActivity.this,
new String[] {Manifest.permission.CAMERA},
PERMISSIONS_REQUEST_CAMERA);
return false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.bd_ocr_activity_camera);
takePictureContainer = (OCRCameraLayout) findViewById(R.id.take_picture_container);
confirmResultContainer = (OCRCameraLayout) findViewById(R.id.confirm_result_container);
cameraView = (CameraView) findViewById(R.id.camera_view);
cameraView.getCameraControl().setPermissionCallback(permissionCallback);
lightButton = (ImageView) findViewById(R.id.light_button);
lightButton.setOnClickListener(lightButtonOnClickListener);
takePhotoBtn = (ImageView) findViewById(R.id.take_photo_button);
findViewById(R.id.album_button).setOnClickListener(albumButtonOnClickListener);
takePhotoBtn.setOnClickListener(takeButtonOnClickListener);
// confirm result;
displayImageView = (ImageView) findViewById(R.id.display_image_view);
confirmResultContainer.findViewById(R.id.confirm_button).setOnClickListener(confirmButtonOnClickListener);
confirmResultContainer.findViewById(R.id.cancel_button).setOnClickListener(confirmCancelButtonOnClickListener);
findViewById(R.id.rotate_button).setOnClickListener(rotateButtonOnClickListener);
cropView = (CropView) findViewById(R.id.crop_view);
cropContainer = (OCRCameraLayout) findViewById(R.id.crop_container);
overlayView = (FrameOverlayView) findViewById(R.id.overlay_view);
cropContainer.findViewById(R.id.confirm_button).setOnClickListener(cropConfirmButtonListener);
cropMaskView = (MaskView) cropContainer.findViewById(R.id.crop_mask_view);
cropContainer.findViewById(R.id.cancel_button).setOnClickListener(cropCancelButtonListener);
setOrientation(getResources().getConfiguration());
initParams();
cameraView.setAutoPictureCallback(autoTakePictureCallback);
}
@Override
protected void onStart() {
super.onStart();
}
@Override
protected void onStop() {
super.onStop();
}
@Override
protected void onPause() {
super.onPause();
cameraView.stop();
}
@Override
protected void onResume() {
super.onResume();
cameraView.start();
}
private void initParams() {
String outputPath = getIntent().getStringExtra(KEY_OUTPUT_FILE_PATH);
final String token = getIntent().getStringExtra(KEY_NATIVE_TOKEN);
isNativeEnable = getIntent().getBooleanExtra(KEY_NATIVE_ENABLE, true);
isNativeManual = getIntent().getBooleanExtra(KEY_NATIVE_MANUAL, false);
if (token == null && !isNativeManual) {
isNativeEnable = false;
}
if (outputPath != null) {
outputFile = new File(outputPath);
}
contentType = getIntent().getStringExtra(KEY_CONTENT_TYPE);
if (contentType == null) {
contentType = CONTENT_TYPE_GENERAL;
}
int maskType;
switch (contentType) {
case CONTENT_TYPE_ID_CARD_FRONT:
maskType = MaskView.MASK_TYPE_ID_CARD_FRONT;
overlayView.setVisibility(View.INVISIBLE);
if (isNativeEnable) {
takePhotoBtn.setVisibility(View.INVISIBLE);
}
break;
case CONTENT_TYPE_ID_CARD_BACK:
maskType = MaskView.MASK_TYPE_ID_CARD_BACK;
overlayView.setVisibility(View.INVISIBLE);
if (isNativeEnable) {
takePhotoBtn.setVisibility(View.INVISIBLE);
}
break;
case CONTENT_TYPE_BANK_CARD:
maskType = MaskView.MASK_TYPE_BANK_CARD;
overlayView.setVisibility(View.INVISIBLE);
break;
case CONTENT_TYPE_PASSPORT:
maskType = MaskView.MASK_TYPE_PASSPORT;
overlayView.setVisibility(View.INVISIBLE);
break;
case CONTENT_TYPE_GENERAL:
default:
maskType = MaskView.MASK_TYPE_NONE;
cropMaskView.setVisibility(View.INVISIBLE);
break;
}
// 身份证本地能力初始化
if (maskType == MaskView.MASK_TYPE_ID_CARD_FRONT || maskType == MaskView.MASK_TYPE_ID_CARD_BACK) {
if (isNativeEnable && !isNativeManual) {
initNative(token);
}
}
cameraView.setEnableScan(isNativeEnable);
cameraView.setMaskType(maskType, this);
cropMaskView.setMaskType(maskType);
}
private void initNative(final String token) {
CameraNativeHelper.init(CameraActivity.this, token,
new CameraNativeHelper.CameraNativeInitCallback() {
@Override
public void onError(int errorCode, Throwable e) {
cameraView.setInitNativeStatus(errorCode);
}
});
}
private void showTakePicture() {
cameraView.getCameraControl().resume();
updateFlashMode();
takePictureContainer.setVisibility(View.VISIBLE);
confirmResultContainer.setVisibility(View.INVISIBLE);
cropContainer.setVisibility(View.INVISIBLE);
}
private void showCrop() {
cameraView.getCameraControl().pause();
updateFlashMode();
takePictureContainer.setVisibility(View.INVISIBLE);
confirmResultContainer.setVisibility(View.INVISIBLE);
cropContainer.setVisibility(View.VISIBLE);
}
private void showResultConfirm() {
cameraView.getCameraControl().pause();
updateFlashMode();
takePictureContainer.setVisibility(View.INVISIBLE);
confirmResultContainer.setVisibility(View.VISIBLE);
cropContainer.setVisibility(View.INVISIBLE);
}
// take photo;
private void updateFlashMode() {
int flashMode = cameraView.getCameraControl().getFlashMode();
if (flashMode == ICameraControl.FLASH_MODE_TORCH) {
lightButton.setImageResource(R.drawable.bd_ocr_light_on);
} else {
lightButton.setImageResource(R.drawable.bd_ocr_light_off);
}
}
private View.OnClickListener albumButtonOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
ActivityCompat.requestPermissions(CameraActivity.this,
new String[] {Manifest.permission.READ_EXTERNAL_STORAGE},
PERMISSIONS_EXTERNAL_STORAGE);
return;
}
}
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
startActivityForResult(intent, REQUEST_CODE_PICK_IMAGE);
}
};
private View.OnClickListener lightButtonOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (cameraView.getCameraControl().getFlashMode() == ICameraControl.FLASH_MODE_OFF) {
cameraView.getCameraControl().setFlashMode(ICameraControl.FLASH_MODE_TORCH);
} else {
cameraView.getCameraControl().setFlashMode(ICameraControl.FLASH_MODE_OFF);
}
updateFlashMode();
}
};
private View.OnClickListener takeButtonOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
cameraView.takePicture(outputFile, takePictureCallback);
}
};
private CameraView.OnTakePictureCallback autoTakePictureCallback = new CameraView.OnTakePictureCallback() {
@Override
public void onPictureTaken(final Bitmap bitmap) {
CameraThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
bitmap.recycle();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
Intent intent = new Intent();
intent.putExtra(CameraActivity.KEY_CONTENT_TYPE, contentType);
setResult(Activity.RESULT_OK, intent);
finish();
}
});
}
};
private CameraView.OnTakePictureCallback takePictureCallback = new CameraView.OnTakePictureCallback() {
@Override
public void onPictureTaken(final Bitmap bitmap) {
handler.post(new Runnable() {
@Override
public void run() {
takePictureContainer.setVisibility(View.INVISIBLE);
if (cropMaskView.getMaskType() == MaskView.MASK_TYPE_NONE) {
cropView.setFilePath(outputFile.getAbsolutePath());
showCrop();
} else if (cropMaskView.getMaskType() == MaskView.MASK_TYPE_BANK_CARD) {
cropView.setFilePath(outputFile.getAbsolutePath());
cropMaskView.setVisibility(View.INVISIBLE);
overlayView.setVisibility(View.VISIBLE);
overlayView.setTypeWide();
showCrop();
} else {
displayImageView.setImageBitmap(bitmap);
showResultConfirm();
}
}
});
}
};
private View.OnClickListener cropCancelButtonListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
// 释放 cropView中的bitmap;
cropView.setFilePath(null);
showTakePicture();
}
};
private View.OnClickListener cropConfirmButtonListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
int maskType = cropMaskView.getMaskType();
Rect rect;
switch (maskType) {
case MaskView.MASK_TYPE_BANK_CARD:
case MaskView.MASK_TYPE_ID_CARD_BACK:
case MaskView.MASK_TYPE_ID_CARD_FRONT:
rect = cropMaskView.getFrameRect();
break;
case MaskView.MASK_TYPE_NONE:
default:
rect = overlayView.getFrameRect();
break;
}
Bitmap cropped = cropView.crop(rect);
displayImageView.setImageBitmap(cropped);
cropAndConfirm();
}
};
private void cropAndConfirm() {
cameraView.getCameraControl().pause();
updateFlashMode();
doConfirmResult();
}
private void doConfirmResult() {
CameraThreadPool.execute(new Runnable() {
@Override
public void run() {
try {
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
Bitmap bitmap = ((BitmapDrawable) displayImageView.getDrawable()).getBitmap();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fileOutputStream);
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
Intent intent = new Intent();
intent.putExtra(CameraActivity.KEY_CONTENT_TYPE, contentType);
setResult(Activity.RESULT_OK, intent);
finish();
}
});
}
private View.OnClickListener confirmButtonOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
doConfirmResult();
}
};
private View.OnClickListener confirmCancelButtonOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
displayImageView.setImageBitmap(null);
showTakePicture();
}
};
private View.OnClickListener rotateButtonOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
cropView.rotate(90);
}
};
private String getRealPathFromURI(Uri contentURI) {
String result;
Cursor cursor = null;
try {
cursor = getContentResolver().query(contentURI, null, null, null, null);
} catch (Throwable e) {
e.printStackTrace();
}
if (cursor == null) {
result = contentURI.getPath();
} else {
cursor.moveToFirst();
int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
result = cursor.getString(idx);
cursor.close();
}
return result;
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setOrientation(newConfig);
}
private void setOrientation(Configuration newConfig) {
int rotation = getWindowManager().getDefaultDisplay().getRotation();
int orientation;
int cameraViewOrientation = CameraView.ORIENTATION_PORTRAIT;
switch (newConfig.orientation) {
case Configuration.ORIENTATION_PORTRAIT:
cameraViewOrientation = CameraView.ORIENTATION_PORTRAIT;
orientation = OCRCameraLayout.ORIENTATION_PORTRAIT;
break;
case Configuration.ORIENTATION_LANDSCAPE:
orientation = OCRCameraLayout.ORIENTATION_HORIZONTAL;
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_90) {
cameraViewOrientation = CameraView.ORIENTATION_HORIZONTAL;
} else {
cameraViewOrientation = CameraView.ORIENTATION_INVERT;
}
break;
default:
orientation = OCRCameraLayout.ORIENTATION_PORTRAIT;
cameraView.setOrientation(CameraView.ORIENTATION_PORTRAIT);
break;
}
takePictureContainer.setOrientation(orientation);
cameraView.setOrientation(cameraViewOrientation);
cropContainer.setOrientation(orientation);
confirmResultContainer.setOrientation(orientation);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_PICK_IMAGE) {
if (resultCode == Activity.RESULT_OK) {
Uri uri = data.getData();
cropView.setFilePath(getRealPathFromURI(uri));
showCrop();
} else {
cameraView.getCameraControl().resume();
}
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSIONS_REQUEST_CAMERA: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
cameraView.getCameraControl().refreshPermission();
} else {
Toast.makeText(getApplicationContext(), R.string.camera_permission_required, Toast.LENGTH_LONG)
.show();
}
break;
}
case PERMISSIONS_EXTERNAL_STORAGE:
default:
break;
}
}
/**
* 做一些收尾工作
*
*/
private void doClear() {
CameraThreadPool.cancelAutoFocusTimer();
if (isNativeEnable && !isNativeManual) {
IDcardQualityProcess.getInstance().releaseModel();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
this.doClear();
}
}
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2018 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.camera;
import android.content.Context;
import com.baidu.idcardquality.IDcardQualityProcess;
/**
* Created by ruanshimin on 2018/1/23.
*/
public class CameraNativeHelper {
public interface CameraNativeInitCallback {
/**
* 加载本地库异常回调
*
* @param errorCode 错误代码
* @param e 如果加载so异常则会有异常对象传入
*/
void onError(int errorCode, Throwable e);
}
public static void init(final Context ctx, final String token, final CameraNativeInitCallback cb) {
CameraThreadPool.execute(new Runnable() {
@Override
public void run() {
int status;
// 加载本地so失败, 异常返回getloadSoException
if (IDcardQualityProcess.getLoadSoException() != null) {
status = CameraView.NATIVE_SOLOAD_FAIL;
cb.onError(status, IDcardQualityProcess.getLoadSoException());
return;
}
// 授权状态
int authStatus = IDcardQualityProcess.init(token);
if (authStatus != 0) {
cb.onError(CameraView.NATIVE_AUTH_FAIL, null);
return;
}
// 加载模型状态
int initModelStatus = IDcardQualityProcess.getInstance()
.idcardQualityInit(ctx.getAssets(),
"models");
if (initModelStatus != 0) {
cb.onError(CameraView.NATIVE_INIT_FAIL, null);
}
}
});
}
public static void release() {
IDcardQualityProcess.getInstance().releaseModel();
}
}
@@ -0,0 +1,66 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.camera;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CameraThreadPool {
static Timer timerFocus = null;
/*
* 对焦频率
*/
static final long cameraScanInterval = 2000;
/*
* 线程池大小
*/
private static int poolCount = Runtime.getRuntime().availableProcessors();
private static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(poolCount);
/**
* 给线程池添加任务
* @param runnable 任务
*/
public static void execute(Runnable runnable) {
fixedThreadPool.execute(runnable);
}
/**
* 创建一个定时对焦的timer任务
* @param runnable 对焦代码
* @return Timer Timer对象,用来终止自动对焦
*/
public static Timer createAutoFocusTimerTask(final Runnable runnable) {
if (timerFocus != null) {
return timerFocus;
}
timerFocus = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
runnable.run();
}
};
timerFocus.scheduleAtFixedRate(task, 0, cameraScanInterval);
return timerFocus;
}
/**
* 终止自动对焦任务,实际调用了cancel方法并且清空对象
* 但是无法终止执行中的任务,需额外处理
*
*/
public static void cancelAutoFocusTimer() {
if (timerFocus != null) {
timerFocus.cancel();
timerFocus = null;
}
}
}
@@ -0,0 +1,650 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.camera;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import com.baidu.idcardquality.IDcardQualityProcess;
import com.baidu.ocr.ui.R;
import com.baidu.ocr.ui.util.DimensionUtil;
import com.baidu.ocr.ui.util.ImageUtil;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapRegionDecoder;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.media.ImageReader;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.IntDef;
/**
* 负责,相机的管理。同时提供,裁剪遮罩功能。
*/
public class CameraView extends FrameLayout {
private int maskType;
/**
* 照相回调
*/
interface OnTakePictureCallback {
void onPictureTaken(Bitmap bitmap);
}
/**
* 垂直方向 {@link #setOrientation(int)}
*/
public static final int ORIENTATION_PORTRAIT = 0;
/**
* 水平方向 {@link #setOrientation(int)}
*/
public static final int ORIENTATION_HORIZONTAL = 90;
/**
* 水平翻转方向 {@link #setOrientation(int)}
*/
public static final int ORIENTATION_INVERT = 270;
/**
* 本地模型授权,加载成功
*/
public static final int NATIVE_AUTH_INIT_SUCCESS = 0;
/**
* 本地模型授权,缺少SO
*/
public static final int NATIVE_SOLOAD_FAIL = 10;
/**
* 本地模型授权,授权失败,token异常
*/
public static final int NATIVE_AUTH_FAIL = 11;
/**
* 本地模型授权,模型加载失败
*/
public static final int NATIVE_INIT_FAIL = 12;
/**
* 是否已经通过本地质量控制扫描
*/
private final int SCAN_SUCCESS = 0;
public void setInitNativeStatus(int initNativeStatus) {
this.initNativeStatus = initNativeStatus;
}
/**
* 本地检测初始化,模型加载标识
*/
private int initNativeStatus = NATIVE_AUTH_INIT_SUCCESS;
@IntDef({ORIENTATION_PORTRAIT, ORIENTATION_HORIZONTAL, ORIENTATION_INVERT})
public @interface Orientation {
}
private CameraViewTakePictureCallback cameraViewTakePictureCallback = new CameraViewTakePictureCallback();
private ICameraControl cameraControl;
/**
* 相机预览View
*/
private View displayView;
/**
* 身份证,银行卡,等裁剪用的遮罩
*/
private MaskView maskView;
/**
* 用于显示提示证 "请对齐身份证正面" 之类的背景
*/
private ImageView hintView;
/**
* 用于显示提示证 "请对齐身份证正面" 之类的文字
*/
private TextView hintViewText;
/**
* 提示文案容器
*/
private LinearLayout hintViewTextWrapper;
/**
* 是否是本地质量控制扫描
*/
private boolean isEnableScan;
public void setEnableScan(boolean enableScan) {
isEnableScan = enableScan;
}
/**
* UI线程的handler
*/
Handler uiHandler = new Handler(Looper.getMainLooper());
public ICameraControl getCameraControl() {
return cameraControl;
}
public void setOrientation(@Orientation int orientation) {
cameraControl.setDisplayOrientation(orientation);
}
public CameraView(Context context) {
super(context);
init();
}
public CameraView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CameraView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void start() {
cameraControl.start();
setKeepScreenOn(true);
}
public void stop() {
cameraControl.stop();
setKeepScreenOn(false);
}
public void takePicture(final File file, final OnTakePictureCallback callback) {
cameraViewTakePictureCallback.file = file;
cameraViewTakePictureCallback.callback = callback;
cameraControl.takePicture(cameraViewTakePictureCallback);
}
private OnTakePictureCallback autoPictureCallback;
public void setAutoPictureCallback(OnTakePictureCallback callback) {
autoPictureCallback = callback;
}
public void setMaskType(@MaskView.MaskType int maskType, final Context ctx) {
maskView.setMaskType(maskType);
maskView.setVisibility(VISIBLE);
hintView.setVisibility(VISIBLE);
int hintResourceId = R.drawable.bd_ocr_hint_align_id_card;
this.maskType = maskType;
boolean isNeedSetImage = true;
switch (maskType) {
case MaskView.MASK_TYPE_ID_CARD_FRONT:
hintResourceId = R.drawable.bd_ocr_round_corner;
isNeedSetImage = false;
break;
case MaskView.MASK_TYPE_ID_CARD_BACK:
isNeedSetImage = false;
hintResourceId = R.drawable.bd_ocr_round_corner;
break;
case MaskView.MASK_TYPE_BANK_CARD:
hintResourceId = R.drawable.bd_ocr_hint_align_bank_card;
break;
case MaskView.MASK_TYPE_PASSPORT:
hintView.setVisibility(INVISIBLE);
break;
case MaskView.MASK_TYPE_NONE:
default:
maskView.setVisibility(INVISIBLE);
hintView.setVisibility(INVISIBLE);
break;
}
if (isNeedSetImage) {
hintView.setImageResource(hintResourceId);
hintViewTextWrapper.setVisibility(INVISIBLE);
}
if (maskType == MaskView.MASK_TYPE_ID_CARD_FRONT && isEnableScan) {
cameraControl.setDetectCallback(new ICameraControl.OnDetectPictureCallback() {
@Override
public int onDetect(byte[] data, int rotation) {
return detect(data, rotation);
}
});
}
if (maskType == MaskView.MASK_TYPE_ID_CARD_BACK && isEnableScan) {
cameraControl.setDetectCallback(new ICameraControl.OnDetectPictureCallback() {
@Override
public int onDetect(byte[] data, int rotation) {
return detect(data, rotation);
}
});
}
}
private int detect(byte[] data, final int rotation) {
if (initNativeStatus != NATIVE_AUTH_INIT_SUCCESS) {
showTipMessage(initNativeStatus);
return 1;
}
// 扫描成功阻止多余的操作
if (cameraControl.getAbortingScan().get()) {
return 0;
}
Rect previewFrame = cameraControl.getPreviewFrame();
if (maskView.getWidth() == 0 || maskView.getHeight() == 0
|| previewFrame.width() == 0 || previewFrame.height() == 0) {
return 0;
}
// BitmapRegionDecoder不会将整个图片加载到内存。
BitmapRegionDecoder decoder = null;
try {
decoder = BitmapRegionDecoder.newInstance(data, 0, data.length, true);
} catch (IOException e) {
e.printStackTrace();
}
int width = rotation % 180 == 0 ? decoder.getWidth() : decoder.getHeight();
int height = rotation % 180 == 0 ? decoder.getHeight() : decoder.getWidth();
Rect frameRect = maskView.getFrameRectExtend();
int left = width * frameRect.left / maskView.getWidth();
int top = height * frameRect.top / maskView.getHeight();
int right = width * frameRect.right / maskView.getWidth();
int bottom = height * frameRect.bottom / maskView.getHeight();
// 高度大于图片
if (previewFrame.top < 0) {
// 宽度对齐。
int adjustedPreviewHeight = previewFrame.height() * getWidth() / previewFrame.width();
int topInFrame = ((adjustedPreviewHeight - frameRect.height()) / 2)
* getWidth() / previewFrame.width();
int bottomInFrame = ((adjustedPreviewHeight + frameRect.height()) / 2) * getWidth()
/ previewFrame.width();
// 等比例投射到照片当中。
top = topInFrame * height / previewFrame.height();
bottom = bottomInFrame * height / previewFrame.height();
} else {
// 宽度大于图片
if (previewFrame.left < 0) {
// 高度对齐
int adjustedPreviewWidth = previewFrame.width() * getHeight() / previewFrame.height();
int leftInFrame = ((adjustedPreviewWidth - maskView.getFrameRect().width()) / 2) * getHeight()
/ previewFrame.height();
int rightInFrame = ((adjustedPreviewWidth + maskView.getFrameRect().width()) / 2) * getHeight()
/ previewFrame.height();
// 等比例投射到照片当中。
left = leftInFrame * width / previewFrame.width();
right = rightInFrame * width / previewFrame.width();
}
}
Rect region = new Rect();
region.left = left;
region.top = top;
region.right = right;
region.bottom = bottom;
// 90度或者270度旋转
if (rotation % 180 == 90) {
int x = decoder.getWidth() / 2;
int y = decoder.getHeight() / 2;
int rotatedWidth = region.height();
int rotated = region.width();
// 计算,裁剪框旋转后的坐标
region.left = x - rotatedWidth / 2;
region.top = y - rotated / 2;
region.right = x + rotatedWidth / 2;
region.bottom = y + rotated / 2;
region.sort();
}
BitmapFactory.Options options = new BitmapFactory.Options();
// 最大图片大小。
int maxPreviewImageSize = 2560;
int size = Math.min(decoder.getWidth(), decoder.getHeight());
size = Math.min(size, maxPreviewImageSize);
options.inSampleSize = ImageUtil.calculateInSampleSize(options, size, size);
options.inScaled = true;
options.inDensity = Math.max(options.outWidth, options.outHeight);
options.inTargetDensity = size;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = decoder.decodeRegion(region, options);
if (rotation != 0) {
// 只能是裁剪完之后再旋转了。有没有别的更好的方案呢?
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
Bitmap rotatedBitmap = Bitmap.createBitmap(
bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
if (bitmap != rotatedBitmap) {
// 有时候 createBitmap会复用对象
bitmap.recycle();
}
bitmap = rotatedBitmap;
}
final int status;
// 调用本地质量控制请求
switch (maskType) {
case MaskView.MASK_TYPE_ID_CARD_FRONT:
status = IDcardQualityProcess.getInstance().idcardQualityDetectionImg(bitmap, true);
break;
case MaskView.MASK_TYPE_ID_CARD_BACK:
status = IDcardQualityProcess.getInstance().idcardQualityDetectionImg(bitmap, false);
break;
default:
status = 1;
}
// 当有某个扫描处理线程调用成功后,阻止其他线程继续调用本地控制代码
if (status == SCAN_SUCCESS) {
// 扫描成功阻止多线程同时回调
if (!cameraControl.getAbortingScan().compareAndSet(false, true)) {
bitmap.recycle();
return 0;
}
autoPictureCallback.onPictureTaken(bitmap);
}
showTipMessage(status);
return status;
}
private void showTipMessage(final int status) {
// 提示tip文字变化
uiHandler.post(new Runnable() {
@Override
public void run() {
if (status == 0) {
hintViewText.setVisibility(View.INVISIBLE);
} else if (!cameraControl.getAbortingScan().get()) {
hintViewText.setVisibility(View.VISIBLE);
hintViewText.setText(getScanMessage(status));
}
}
});
}
private String getScanMessage(int status) {
String message;
switch (status) {
case 0:
message = "";
break;
case 2:
message = "身份证模糊,请重新尝试";
break;
case 3:
message = "身份证反光,请重新尝试";
break;
case 4:
message = "请将身份证前后反转再进行识别";
break;
case 5:
message = "请拿稳镜头和身份证";
break;
case 6:
message = "请将镜头靠近身份证";
break;
case 7:
message = "请将身份证完整置于取景框内";
break;
case NATIVE_AUTH_FAIL:
message = "本地质量控制授权失败";
break;
case NATIVE_INIT_FAIL:
message = "本地模型加载失败";
break;
case NATIVE_SOLOAD_FAIL:
message = "本地SO库加载失败";
break;
case 1:
default:
message = "请将身份证置于取景框内";
}
return message;
}
private void init() {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// cameraControl = new Camera2Control(getContext());
// } else {
//
// }
cameraControl = new Camera1Control(getContext());
displayView = cameraControl.getDisplayView();
addView(displayView);
maskView = new MaskView(getContext());
addView(maskView);
hintView = new ImageView(getContext());
addView(hintView);
hintViewTextWrapper = new LinearLayout(getContext());
hintViewTextWrapper.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
DimensionUtil.dpToPx(25));
lp.gravity = Gravity.CENTER;
hintViewText = new TextView(getContext());
hintViewText.setBackgroundResource(R.drawable.bd_ocr_round_corner);
hintViewText.setAlpha(0.5f);
hintViewText.setPadding(DimensionUtil.dpToPx(10), 0, DimensionUtil.dpToPx(10), 0);
hintViewTextWrapper.addView(hintViewText, lp);
hintViewText.setGravity(Gravity.CENTER);
hintViewText.setTextColor(Color.WHITE);
hintViewText.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
hintViewText.setText(getScanMessage(-1));
addView(hintViewTextWrapper, lp);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
displayView.layout(left, 0, right, bottom - top);
maskView.layout(left, 0, right, bottom - top);
int hintViewWidth = DimensionUtil.dpToPx(250);
int hintViewHeight = DimensionUtil.dpToPx(25);
int hintViewLeft = (getWidth() - hintViewWidth) / 2;
int hintViewTop = maskView.getFrameRect().bottom + DimensionUtil.dpToPx(16);
hintViewTextWrapper.layout(hintViewLeft, hintViewTop,
hintViewLeft + hintViewWidth, hintViewTop + hintViewHeight);
hintView.layout(hintViewLeft, hintViewTop,
hintViewLeft + hintViewWidth, hintViewTop + hintViewHeight);
}
/**
* 拍摄后的照片。需要进行裁剪。有些手机(比如三星)不会对照片数据进行旋转,而是将旋转角度写入EXIF信息当中,
* 所以需要做旋转处理。
*
* @param outputFile 写入照片的文件。
* @param data 原始照片数据。
* @param rotation 照片exif中的旋转角度。
*
* @return 裁剪好的bitmap。
*/
@SuppressWarnings("ResultOfMethodCallIgnored")
private Bitmap crop(File outputFile, byte[] data, int rotation) {
try {
Rect previewFrame = cameraControl.getPreviewFrame();
if (maskView.getWidth() == 0 || maskView.getHeight() == 0
|| previewFrame.width() == 0 || previewFrame.height() == 0) {
return null;
}
// BitmapRegionDecoder不会将整个图片加载到内存。
BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(data, 0, data.length, true);
int width = rotation % 180 == 0 ? decoder.getWidth() : decoder.getHeight();
int height = rotation % 180 == 0 ? decoder.getHeight() : decoder.getWidth();
Rect frameRect = maskView.getFrameRect();
int left = width * frameRect.left / maskView.getWidth();
int top = height * frameRect.top / maskView.getHeight();
int right = width * frameRect.right / maskView.getWidth();
int bottom = height * frameRect.bottom / maskView.getHeight();
// 高度大于图片
if (previewFrame.top < 0) {
// 宽度对齐。
int adjustedPreviewHeight = previewFrame.height() * getWidth() / previewFrame.width();
int topInFrame = ((adjustedPreviewHeight - frameRect.height()) / 2)
* getWidth() / previewFrame.width();
int bottomInFrame = ((adjustedPreviewHeight + frameRect.height()) / 2) * getWidth()
/ previewFrame.width();
// 等比例投射到照片当中。
top = topInFrame * height / previewFrame.height();
bottom = bottomInFrame * height / previewFrame.height();
} else {
// 宽度大于图片
if (previewFrame.left < 0) {
// 高度对齐
int adjustedPreviewWidth = previewFrame.width() * getHeight() / previewFrame.height();
int leftInFrame = ((adjustedPreviewWidth - maskView.getFrameRect().width()) / 2) * getHeight()
/ previewFrame.height();
int rightInFrame = ((adjustedPreviewWidth + maskView.getFrameRect().width()) / 2) * getHeight()
/ previewFrame.height();
// 等比例投射到照片当中。
left = leftInFrame * width / previewFrame.width();
right = rightInFrame * width / previewFrame.width();
}
}
Rect region = new Rect();
region.left = left;
region.top = top;
region.right = right;
region.bottom = bottom;
// 90度或者270度旋转
if (rotation % 180 == 90) {
int x = decoder.getWidth() / 2;
int y = decoder.getHeight() / 2;
int rotatedWidth = region.height();
int rotated = region.width();
// 计算,裁剪框旋转后的坐标
region.left = x - rotatedWidth / 2;
region.top = y - rotated / 2;
region.right = x + rotatedWidth / 2;
region.bottom = y + rotated / 2;
region.sort();
}
BitmapFactory.Options options = new BitmapFactory.Options();
// 最大图片大小。
int maxPreviewImageSize = 2560;
int size = Math.min(decoder.getWidth(), decoder.getHeight());
size = Math.min(size, maxPreviewImageSize);
options.inSampleSize = ImageUtil.calculateInSampleSize(options, size, size);
options.inScaled = true;
options.inDensity = Math.max(options.outWidth, options.outHeight);
options.inTargetDensity = size;
options.inPreferredConfig = Bitmap.Config.RGB_565;
Bitmap bitmap = decoder.decodeRegion(region, options);
if (rotation != 0) {
// 只能是裁剪完之后再旋转了。有没有别的更好的方案呢?
Matrix matrix = new Matrix();
matrix.postRotate(rotation);
Bitmap rotatedBitmap = Bitmap.createBitmap(
bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
if (bitmap != rotatedBitmap) {
// 有时候 createBitmap会复用对象
bitmap.recycle();
}
bitmap = rotatedBitmap;
}
try {
if (!outputFile.exists()) {
outputFile.createNewFile();
}
FileOutputStream fileOutputStream = new FileOutputStream(outputFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fileOutputStream);
fileOutputStream.flush();
fileOutputStream.close();
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public void release() {
IDcardQualityProcess.getInstance().releaseModel();
}
private class CameraViewTakePictureCallback implements ICameraControl.OnTakePictureCallback {
private File file;
private OnTakePictureCallback callback;
@Override
public void onPictureTaken(final byte[] data) {
CameraThreadPool.execute(new Runnable() {
@Override
public void run() {
final int rotation = ImageUtil.getOrientation(data);
Bitmap bitmap = crop(file, data, rotation);
callback.onPictureTaken(bitmap);
}
});
}
}
}
@@ -0,0 +1,121 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.camera;
import android.graphics.Rect;
import android.view.View;
import androidx.annotation.IntDef;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Android 5.0 相机的API发生很大的变化。些类屏蔽掉了 api的变化。相机的操作和功能,抽象剥离出来。
*/
public interface ICameraControl {
/**
* 闪光灯关 {@link #setFlashMode(int)}
*/
int FLASH_MODE_OFF = 0;
/**
* 闪光灯开 {@link #setFlashMode(int)}
*/
int FLASH_MODE_TORCH = 1;
/**
* 闪光灯自动 {@link #setFlashMode(int)}
*/
int FLASH_MODE_AUTO = 2;
@IntDef({FLASH_MODE_TORCH, FLASH_MODE_OFF, FLASH_MODE_AUTO})
@interface FlashMode {
}
/**
* 照相回调。
*/
interface OnTakePictureCallback {
void onPictureTaken(byte[] data);
}
/**
* 设置本地质量控制回调,如果不设置则视为不扫描调用本地质量控制代码。
*/
void setDetectCallback(OnDetectPictureCallback callback);
/**
* 预览回调
*/
interface OnDetectPictureCallback {
int onDetect(byte[] data, int rotation);
}
/**
* 打开相机。
*/
void start();
/**
* 关闭相机
*/
void stop();
void pause();
void resume();
/**
* 相机对应的预览视图。
* @return 预览视图
*/
View getDisplayView();
/**
* 看到的预览可能不是照片的全部。返回预览视图的全貌。
* @return 预览视图frame;
*/
Rect getPreviewFrame();
/**
* 拍照。结果在回调中获取。
* @param callback 拍照结果回调
*/
void takePicture(OnTakePictureCallback callback);
/**
* 设置权限回调,当手机没有拍照权限时,可在回调中获取。
* @param callback 权限回调
*/
void setPermissionCallback(PermissionCallback callback);
/**
* 设置水平方向
* @param displayOrientation 参数值见 {@link com.baidu.ocr.ui.camera.CameraView.Orientation}
*/
void setDisplayOrientation(@CameraView.Orientation int displayOrientation);
/**
* 获取到拍照权限时,调用些函数以继续。
*/
void refreshPermission();
/**
* 获取已经扫描成功,处理中
*/
AtomicBoolean getAbortingScan();
/**
* 设置闪光灯状态。
* @param flashMode {@link #FLASH_MODE_TORCH,#FLASH_MODE_OFF,#FLASH_MODE_AUTO}
*/
void setFlashMode(@FlashMode int flashMode);
/**
* 获取当前闪光灯状态
* @return 当前闪光灯状态 参见 {@link #setFlashMode(int)}
*/
@FlashMode
int getFlashMode();
}
@@ -0,0 +1,279 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.camera;
import java.io.File;
import com.baidu.ocr.ui.R;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.IntDef;
import androidx.annotation.RequiresApi;
import androidx.core.content.res.ResourcesCompat;
@SuppressWarnings("unused")
public class MaskView extends View {
public static final int MASK_TYPE_NONE = 0;
public static final int MASK_TYPE_ID_CARD_FRONT = 1;
public static final int MASK_TYPE_ID_CARD_BACK = 2;
public static final int MASK_TYPE_BANK_CARD = 11;
public static final int MASK_TYPE_PASSPORT = 21;
@IntDef({MASK_TYPE_NONE, MASK_TYPE_ID_CARD_FRONT, MASK_TYPE_ID_CARD_BACK, MASK_TYPE_BANK_CARD,
MASK_TYPE_PASSPORT})
@interface MaskType {
}
public void setLineColor(int lineColor) {
this.lineColor = lineColor;
}
public void setMaskColor(int maskColor) {
this.maskColor = maskColor;
}
private int lineColor = Color.WHITE;
private int maskType = MASK_TYPE_ID_CARD_FRONT;
private int maskColor = Color.argb(100, 0, 0, 0);
private Paint eraser = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint pen = new Paint(Paint.ANTI_ALIAS_FLAG);
private Rect frame = new Rect();
private Rect framePassport = new Rect();
private Drawable locatorDrawable;
public Rect getFrameRect() {
if (maskType == MASK_TYPE_NONE) {
return new Rect(0, 0, getWidth(), getHeight());
} else if (maskType == MASK_TYPE_PASSPORT) {
return new Rect(framePassport);
} else {
return new Rect(frame);
}
}
public Rect getFrameRectExtend() {
Rect rc = new Rect(frame);
int widthExtend = (int) ((frame.right - frame.left) * 0.02f);
int heightExtend = (int) ((frame.bottom - frame.top) * 0.02f);
rc.left -= widthExtend;
rc.right += widthExtend;
rc.top -= heightExtend;
rc.bottom += heightExtend;
return rc;
}
public void setMaskType(@MaskType int maskType) {
this.maskType = maskType;
switch (maskType) {
case MASK_TYPE_ID_CARD_FRONT:
locatorDrawable = ResourcesCompat.getDrawable(getResources(),
R.drawable.bd_ocr_id_card_locator_front, null);
break;
case MASK_TYPE_ID_CARD_BACK:
locatorDrawable = ResourcesCompat.getDrawable(getResources(),
R.drawable.bd_ocr_id_card_locator_back, null);
break;
case MASK_TYPE_PASSPORT:
locatorDrawable = ResourcesCompat.getDrawable(getResources(),
R.drawable.bd_ocr_passport_locator, null);
break;
case MASK_TYPE_BANK_CARD:
break;
case MASK_TYPE_NONE:
default:
break;
}
invalidate();
}
public int getMaskType() {
return maskType;
}
public void setOrientation(@CameraView.Orientation int orientation) {
}
public MaskView(Context context) {
super(context);
init();
}
public MaskView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public MaskView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
locatorDrawable = ResourcesCompat.getDrawable(getResources(), R.drawable.bd_ocr_id_card_locator_front, null);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w > 0 && h > 0) {
if (maskType != MASK_TYPE_PASSPORT) {
float ratio = h > w ? 0.9f : 0.72f;
int width = (int) (w * ratio);
int height = width * 400 / 620;
int left = (w - width) / 2;
int top = (h - height) / 2;
int right = width + left;
int bottom = height + top;
frame.left = left;
frame.top = top;
frame.right = right;
frame.bottom = bottom;
} else {
float ratio = 0.9f;
int width = (int) (w * ratio);
int height = width * 330 / 470;
int left = (w - width) / 2;
int top = (h - height) / 2;
int right = width + left;
int bottom = height + top;
framePassport.left = left;
framePassport.top = top;
framePassport.right = right;
framePassport.bottom = bottom;
}
}
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Rect frame = this.frame;
if (maskType == MASK_TYPE_PASSPORT) {
frame = framePassport;
}
int width = frame.width();
int height = frame.height();
int left = frame.left;
int top = frame.top;
int right = frame.right;
int bottom = frame.bottom;
canvas.drawColor(maskColor);
fillRectRound(left, top, right, bottom, 30, 30, false);
canvas.drawPath(path, pen);
canvas.drawPath(path, eraser);
if (maskType == MASK_TYPE_ID_CARD_FRONT) {
locatorDrawable.setBounds(
(int) (left + 601f / 1006 * width),
(int) (top + (110f / 632) * height),
(int) (left + (963f / 1006) * width),
(int) (top + (476f / 632) * height));
} else if (maskType == MASK_TYPE_ID_CARD_BACK) {
locatorDrawable.setBounds(
(int) (left + 51f / 1006 * width),
(int) (top + (48f / 632) * height),
(int) (left + (250f / 1006) * width),
(int) (top + (262f / 632) * height));
} else if (maskType == MASK_TYPE_PASSPORT) {
locatorDrawable.setBounds(
(int) (left + 30f / 1006 * width),
(int) (top + (20f / 632) * height),
(int) (left + (303f / 1006) * width),
(int) (top + (416f / 632) * height));
}
if (locatorDrawable != null) {
locatorDrawable.draw(canvas);
}
}
private Path path = new Path();
private Path fillRectRound(float left, float top, float right, float bottom, float rx, float ry, boolean
conformToOriginalPost) {
path.reset();
if (rx < 0) {
rx = 0;
}
if (ry < 0) {
ry = 0;
}
float width = right - left;
float height = bottom - top;
if (rx > width / 2) {
rx = width / 2;
}
if (ry > height / 2) {
ry = height / 2;
}
float widthMinusCorners = (width - (2 * rx));
float heightMinusCorners = (height - (2 * ry));
path.moveTo(right, top + ry);
path.rQuadTo(0, -ry, -rx, -ry);
path.rLineTo(-widthMinusCorners, 0);
path.rQuadTo(-rx, 0, -rx, ry);
path.rLineTo(0, heightMinusCorners);
if (conformToOriginalPost) {
path.rLineTo(0, ry);
path.rLineTo(width, 0);
path.rLineTo(0, -ry);
} else {
path.rQuadTo(0, ry, rx, ry);
path.rLineTo(widthMinusCorners, 0);
path.rQuadTo(rx, 0, rx, -ry);
}
path.rLineTo(0, -heightMinusCorners);
path.close();
return path;
}
{
// 硬件加速不支持,图层混合。
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
pen.setColor(Color.WHITE);
pen.setStyle(Paint.Style.STROKE);
pen.setStrokeWidth(6);
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
private void capture(File file) {
}
}
@@ -0,0 +1,166 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.camera;
import com.baidu.ocr.ui.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
public class OCRCameraLayout extends FrameLayout {
public static int ORIENTATION_PORTRAIT = 0;
public static int ORIENTATION_HORIZONTAL = 1;
private int orientation = ORIENTATION_PORTRAIT;
private View contentView;
private View centerView;
private View leftDownView;
private View rightUpView;
private int contentViewId;
private int centerViewId;
private int leftDownViewId;
private int rightUpViewId;
public void setOrientation(int orientation) {
if (this.orientation == orientation) {
return;
}
this.orientation = orientation;
requestLayout();
}
public OCRCameraLayout(Context context) {
super(context);
}
public OCRCameraLayout(Context context, AttributeSet attrs) {
super(context, attrs);
parseAttrs(attrs);
}
public OCRCameraLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
parseAttrs(attrs);
}
{
setWillNotDraw(false);
}
private void parseAttrs(AttributeSet attrs) {
TypedArray a = getContext().getTheme().obtainStyledAttributes(
attrs,
R.styleable.OCRCameraLayout,
0, 0);
try {
contentViewId = a.getResourceId(R.styleable.OCRCameraLayout_contentView, -1);
centerViewId = a.getResourceId(R.styleable.OCRCameraLayout_centerView, -1);
leftDownViewId = a.getResourceId(R.styleable.OCRCameraLayout_leftDownView, -1);
rightUpViewId = a.getResourceId(R.styleable.OCRCameraLayout_rightUpView, -1);
} finally {
a.recycle();
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
contentView = findViewById(contentViewId);
if (centerViewId != -1) {
centerView = findViewById(centerViewId);
}
leftDownView = findViewById(leftDownViewId);
rightUpView = findViewById(rightUpViewId);
}
private Rect backgroundRect = new Rect();
private Paint paint = new Paint();
{
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.argb(83, 0, 0, 0));
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int width = getWidth();
int height = getHeight();
int left;
int top;
ViewGroup.MarginLayoutParams leftDownViewLayoutParams = (MarginLayoutParams) leftDownView.getLayoutParams();
ViewGroup.MarginLayoutParams rightUpViewLayoutParams = (MarginLayoutParams) rightUpView.getLayoutParams();
if (r < b) {
int contentHeight = width * 4 / 3;
int heightLeft = height - contentHeight;
contentView.layout(l, t, r, contentHeight);
backgroundRect.left = 0;
backgroundRect.top = contentHeight;
backgroundRect.right = width;
backgroundRect.bottom = height;
// layout centerView;
if (centerView != null) {
left = (width - centerView.getMeasuredWidth()) / 2;
top = contentHeight + (heightLeft - centerView.getMeasuredHeight()) / 2;
centerView
.layout(left, top, left + centerView.getMeasuredWidth(), top + centerView.getMeasuredHeight());
}
// layout leftDownView
left = leftDownViewLayoutParams.leftMargin;
top = contentHeight + (heightLeft - leftDownView.getMeasuredHeight()) / 2;
leftDownView
.layout(left, top, left + leftDownView.getMeasuredWidth(), top + leftDownView.getMeasuredHeight());
// layout rightUpView
left = width - rightUpView.getMeasuredWidth() - rightUpViewLayoutParams.rightMargin;
top = contentHeight + (heightLeft - rightUpView.getMeasuredHeight()) / 2;
rightUpView.layout(left, top, left + rightUpView.getMeasuredWidth(), top + rightUpView.getMeasuredHeight());
} else {
int contentWidth = height * 4 / 3;
int widthLeft = width - contentWidth;
contentView.layout(l, t, contentWidth, height);
backgroundRect.left = contentWidth;
backgroundRect.top = 0;
backgroundRect.right = width;
backgroundRect.bottom = height;
// layout centerView
if (centerView != null) {
left = contentWidth + (widthLeft - centerView.getMeasuredWidth()) / 2;
top = (height - centerView.getMeasuredHeight()) / 2;
centerView
.layout(left, top, left + centerView.getMeasuredWidth(), top + centerView.getMeasuredHeight());
}
// layout leftDownView
left = contentWidth + (widthLeft - leftDownView.getMeasuredWidth()) / 2;
top = height - leftDownView.getMeasuredHeight() - leftDownViewLayoutParams.bottomMargin;
leftDownView
.layout(left, top, left + leftDownView.getMeasuredWidth(), top + leftDownView.getMeasuredHeight());
// layout rightUpView
left = contentWidth + (widthLeft - rightUpView.getMeasuredWidth()) / 2;
top = rightUpViewLayoutParams.topMargin;
rightUpView.layout(left, top, left + rightUpView.getMeasuredWidth(), top + rightUpView.getMeasuredHeight());
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(backgroundRect, paint);
}
}
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.camera;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class OCRFrameLayout extends ViewGroup {
public OCRFrameLayout(Context context) {
super(context);
}
public OCRFrameLayout(Context context, AttributeSet attrs) {
super(context, attrs);
parseAttrs(attrs);
}
public OCRFrameLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
parseAttrs(attrs);
}
private void parseAttrs(AttributeSet attrs) {
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
view.layout(l, t, r, b);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width;
int height;
int childCount = getChildCount();
width = MeasureSpec.getSize(widthMeasureSpec);
height = MeasureSpec.getSize(heightMeasureSpec);
for (int i = 0; i < childCount; i++) {
View view = getChildAt(i);
measureChild(view, MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec
(height, MeasureSpec.EXACTLY));
}
setMeasuredDimension(resolveSize(width, widthMeasureSpec), resolveSize(height, heightMeasureSpec));
}
}
@@ -0,0 +1,8 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.camera;
public interface PermissionCallback {
boolean onRequestPermission();
}
@@ -0,0 +1,325 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.crop;
import java.io.IOException;
import com.baidu.ocr.ui.util.ImageUtil;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.media.ExifInterface;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.WindowManager;
public class CropView extends View {
public CropView(Context context) {
super(context);
init();
}
public CropView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public CropView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void setFilePath(String path) {
if (this.bitmap != null && !this.bitmap.isRecycled()) {
this.bitmap.recycle();
}
if (path == null) {
return;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap original = BitmapFactory.decodeFile(path, options);
try {
ExifInterface exif = new ExifInterface(path);
int rotation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
Matrix matrix = new Matrix();
int rotationInDegrees = ImageUtil.exifToDegrees(rotation);
if (rotation != 0f) {
matrix.preRotate(rotationInDegrees);
}
// 图片太大会导致内存泄露,所以在显示前对图片进行裁剪。
int maxPreviewImageSize = 2560;
int min = Math.min(options.outWidth, options.outHeight);
min = Math.min(min, maxPreviewImageSize);
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Point screenSize = new Point();
windowManager.getDefaultDisplay().getSize(screenSize);
min = Math.min(min, screenSize.x * 2 / 3);
options.inSampleSize = ImageUtil.calculateInSampleSize(options, min, min);
options.inScaled = true;
options.inDensity = options.outWidth;
options.inTargetDensity = min * options.inSampleSize;
options.inPreferredConfig = Bitmap.Config.RGB_565;
options.inJustDecodeBounds = false;
this.bitmap = BitmapFactory.decodeFile(path, options);
} catch (IOException e) {
e.printStackTrace();
this.bitmap = original;
} catch (NullPointerException e) {
e.printStackTrace();
}
setBitmap(this.bitmap);
}
private void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
matrix.reset();
centerImage(getWidth(), getHeight());
rotation = 0;
invalidate();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
centerImage(w, h);
invalidate();
}
public Bitmap crop(Rect frame) {
float scale = getScale();
float[] src = new float[] {frame.left, frame.top};
float[] desc = new float[] {0, 0};
Matrix invertedMatrix = new Matrix();
this.matrix.invert(invertedMatrix);
invertedMatrix.mapPoints(desc, src);
Matrix matrix = new Matrix();
int width = (int) (frame.width() / scale);
int height = (int) (frame.height() / scale);
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
Bitmap originalBitmap = this.bitmap;
matrix.postTranslate(-desc[0], -desc[1]);
canvas.drawBitmap(originalBitmap, matrix, null);
return bitmap;
}
public void setMinimumScale(float setMinimumScale) {
this.setMinimumScale = setMinimumScale;
}
public void setMaximumScale(float maximumScale) {
this.maximumScale = maximumScale;
}
private float setMinimumScale = 0.2f;
private float maximumScale = 4.0f;
private float[] matrixArray = new float[9];
private Matrix matrix = new Matrix();
private Bitmap bitmap;
private GestureDetector gestureDetector;
private ScaleGestureDetector scaleGestureDetector;
private ScaleGestureDetector.OnScaleGestureListener onScaleGestureListener =
new ScaleGestureDetector.OnScaleGestureListener() {
@Override
public boolean onScale(ScaleGestureDetector detector) {
scale(detector);
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
float scale = detector.getScaleFactor();
matrix.postScale(scale, scale);
invalidate();
}
};
private void init() {
scaleGestureDetector = new ScaleGestureDetector(getContext(), onScaleGestureListener);
gestureDetector = new GestureDetector(getContext(), new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
translate(distanceX, distanceY);
return true;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
});
}
int rotation = 0;
public void rotate(int degrees) {
if (this.bitmap == null) {
return;
}
Matrix matrix = new Matrix();
int dx = this.bitmap.getWidth() / 2;
int dy = this.bitmap.getHeight() / 2;
matrix.postTranslate(-dx, -dy);
matrix.postRotate(degrees);
matrix.postTranslate(dy, dx);
Bitmap scaledBitmap = this.bitmap;
Bitmap rotatedBitmap = Bitmap.createBitmap(scaledBitmap.getHeight(), scaledBitmap.getWidth(),
Bitmap.Config.RGB_565);
Canvas canvas = new Canvas(rotatedBitmap);
canvas.drawBitmap(this.bitmap, matrix, null);
this.bitmap.recycle();
this.bitmap = rotatedBitmap;
centerImage(getWidth(), getHeight());
invalidate();
}
private void translate(float distanceX, float distanceY) {
matrix.getValues(matrixArray);
float left = matrixArray[Matrix.MTRANS_X];
float top = matrixArray[Matrix.MTRANS_Y];
Rect bound = getRestrictedBound();
if (bound != null) {
float scale = getScale();
float right = left + (int) (bitmap.getWidth() / scale);
float bottom = top + (int) (bitmap.getHeight() / scale);
if (left - distanceX > bound.left) {
distanceX = left - bound.left;
}
if (top - distanceY > bound.top) {
distanceY = top - bound.top;
}
if (distanceX > 0) {
if (right - distanceX < bound.right) {
distanceX = right - bound.right;
}
}
if (distanceY > 0) {
if (bottom - distanceY < bound.bottom) {
distanceY = bottom - bound.bottom;
}
}
}
matrix.postTranslate(-distanceX, -distanceY);
invalidate();
}
private void scale(ScaleGestureDetector detector) {
float scale = detector.getScaleFactor();
float currentScale = getScale();
if (currentScale * scale < setMinimumScale) {
scale = setMinimumScale / currentScale;
}
if (currentScale * scale > maximumScale) {
scale = maximumScale / currentScale;
}
matrix.postScale(scale, scale, detector.getFocusX(), detector.getFocusY());
invalidate();
}
private void centerImage(int width, int height) {
if (width <= 0 || height <= 0 || bitmap == null) {
return;
}
float widthRatio = 1.0f * height / this.bitmap.getHeight();
float heightRatio = 1.0f * width / this.bitmap.getWidth();
float ratio = Math.min(widthRatio, heightRatio);
float dx = (width - this.bitmap.getWidth()) / 2;
float dy = (height - this.bitmap.getHeight()) / 2;
matrix.setTranslate(0, 0);
matrix.setScale(ratio, ratio, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
matrix.postTranslate(dx, dy);
invalidate();
}
private float getScale() {
matrix.getValues(matrixArray);
float scale = matrixArray[Matrix.MSCALE_X];
if (Math.abs(scale) <= 0.1) {
scale = matrixArray[Matrix.MSKEW_X];
}
return Math.abs(scale);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (bitmap != null) {
canvas.drawBitmap(bitmap, matrix, null);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = scaleGestureDetector.onTouchEvent(event);
result = gestureDetector.onTouchEvent(event) || result;
return result || super.onTouchEvent(event);
}
private Rect restrictBound;
private Rect getRestrictedBound() {
return restrictBound;
}
public void setRestrictBound(Rect rect) {
this.restrictBound = rect;
}
}
@@ -0,0 +1,290 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.crop;
import com.baidu.ocr.ui.util.DimensionUtil;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
public class FrameOverlayView extends View {
interface OnFrameChangeListener {
void onFrameChange(RectF newFrame);
}
public Rect getFrameRect() {
Rect rect = new Rect();
rect.left = (int) frameRect.left;
rect.top = (int) frameRect.top;
rect.right = (int) frameRect.right;
rect.bottom = (int) frameRect.bottom;
return rect;
}
public FrameOverlayView(Context context) {
super(context);
init();
}
public FrameOverlayView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public FrameOverlayView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private GestureDetector.SimpleOnGestureListener onGestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
translate(distanceX, distanceY);
return true;
}
};
private static final int CORNER_LEFT_TOP = 1;
private static final int CORNER_RIGHT_TOP = 2;
private static final int CORNER_RIGHT_BOTTOM = 3;
private static final int CORNER_LEFT_BOTTOM = 4;
private int currentCorner = -1;
int margin = 20;
int cornerLength = 100;
int cornerLineWidth = 6;
private int maskColor = Color.argb(180, 0, 0, 0);
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
private Paint eraser = new Paint(Paint.ANTI_ALIAS_FLAG);
private GestureDetector gestureDetector;
private RectF touchRect = new RectF();
private RectF frameRect = new RectF();
private OnFrameChangeListener onFrameChangeListener;
{
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
paint.setColor(Color.WHITE);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(6);
eraser.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
public void setOnFrameChangeListener(OnFrameChangeListener onFrameChangeListener) {
this.onFrameChangeListener = onFrameChangeListener;
}
private void init() {
gestureDetector = new GestureDetector(getContext(), onGestureListener);
cornerLength = DimensionUtil.dpToPx(18);
cornerLineWidth = DimensionUtil.dpToPx(3);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
resetFrameRect(w, h);
}
private void resetFrameRect(int w, int h) {
if (shapeType == 1) {
frameRect.left = (int) (w * 0.05);
frameRect.top = (int) (h * 0.25);
} else {
frameRect.left = (int) (w * 0.2);
frameRect.top = (int) (h * 0.2);
}
frameRect.right = w - frameRect.left;
frameRect.bottom = h - frameRect.top;
}
private int shapeType = 0;
public void setTypeWide() {
shapeType = 1;
}
private void translate(float x, float y) {
if (x > 0) {
// moving left;
if (frameRect.left - x < margin) {
x = frameRect.left - margin;
}
} else {
if (frameRect.right - x > getWidth() - margin) {
x = frameRect.right - getWidth() + margin;
}
}
if (y > 0) {
if (frameRect.top - y < margin) {
y = frameRect.top - margin;
}
} else {
if (frameRect.bottom - y > getHeight() - margin) {
y = frameRect.bottom - getHeight() + margin;
}
}
frameRect.offset(-x, -y);
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(maskColor);
paint.setStrokeWidth(DimensionUtil.dpToPx(1));
canvas.drawRect(frameRect, paint);
canvas.drawRect(frameRect, eraser);
drawCorners(canvas);
}
private void drawCorners(Canvas canvas) {
paint.setStrokeWidth(cornerLineWidth);
// left top
drawLine(canvas, frameRect.left - cornerLineWidth / 2, frameRect.top, cornerLength, 0);
drawLine(canvas, frameRect.left, frameRect.top, 0, cornerLength);
// right top
drawLine(canvas, frameRect.right + cornerLineWidth / 2, frameRect.top, -cornerLength, 0);
drawLine(canvas, frameRect.right, frameRect.top, 0, cornerLength);
// right bottom
drawLine(canvas, frameRect.right, frameRect.bottom, 0, -cornerLength);
drawLine(canvas, frameRect.right + cornerLineWidth / 2, frameRect.bottom, -cornerLength, 0);
// left bottom
drawLine(canvas, frameRect.left - cornerLineWidth / 2, frameRect.bottom, cornerLength, 0);
drawLine(canvas, frameRect.left, frameRect.bottom, 0, -cornerLength);
}
private void drawLine(Canvas canvas, float x, float y, int dx, int dy) {
canvas.drawLine(x, y, x + dx, y + dy, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean result = handleDown(event);
float ex = 60;
RectF rectExtend = new RectF(frameRect.left - ex, frameRect.top - ex,
frameRect.right + ex, frameRect.bottom + ex);
if (!result) {
if (rectExtend.contains(event.getX(), event.getY())) {
gestureDetector.onTouchEvent(event);
return true;
}
}
return result;
}
private boolean handleDown(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
currentCorner = -1;
break;
case MotionEvent.ACTION_DOWN: {
float radius = cornerLength;
touchRect.set(event.getX() - radius, event.getY() - radius, event.getX() + radius,
event.getY() + radius);
if (touchRect.contains(frameRect.left, frameRect.top)) {
currentCorner = CORNER_LEFT_TOP;
return true;
}
if (touchRect.contains(frameRect.right, frameRect.top)) {
currentCorner = CORNER_RIGHT_TOP;
return true;
}
if (touchRect.contains(frameRect.right, frameRect.bottom)) {
currentCorner = CORNER_RIGHT_BOTTOM;
return true;
}
if (touchRect.contains(frameRect.left, frameRect.bottom)) {
currentCorner = CORNER_LEFT_BOTTOM;
return true;
}
return false;
}
case MotionEvent.ACTION_MOVE:
return handleScale(event);
default:
}
return false;
}
private boolean handleScale(MotionEvent event) {
switch (currentCorner) {
case CORNER_LEFT_TOP:
scaleTo(event.getX(), event.getY(), frameRect.right, frameRect.bottom);
return true;
case CORNER_RIGHT_TOP:
scaleTo(frameRect.left, event.getY(), event.getX(), frameRect.bottom);
return true;
case CORNER_RIGHT_BOTTOM:
scaleTo(frameRect.left, frameRect.top, event.getX(), event.getY());
return true;
case CORNER_LEFT_BOTTOM:
scaleTo(event.getX(), frameRect.top, frameRect.right, event.getY());
return true;
default:
return false;
}
}
private void scaleTo(float left, float top, float right, float bottom) {
if (bottom - top < getMinimumFrameHeight()) {
top = frameRect.top;
bottom = frameRect.bottom;
}
if (right - left < getMinimumFrameWidth()) {
left = frameRect.left;
right = frameRect.right;
}
left = Math.max(margin, left);
top = Math.max(margin, top);
right = Math.min(getWidth() - margin, right);
bottom = Math.min(getHeight() - margin, bottom);
frameRect.set(left, top, right, bottom);
invalidate();
}
private void notifyFrameChange() {
if (onFrameChangeListener != null) {
onFrameChangeListener.onFrameChange(frameRect);
}
}
private float getMinimumFrameWidth() {
return 2.4f * cornerLength;
}
private float getMinimumFrameHeight() {
return 2.4f * cornerLength;
}
}
@@ -0,0 +1,14 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.util;
import android.content.res.Resources;
public class DimensionUtil {
public static int dpToPx(int dp) {
return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
}
}
@@ -0,0 +1,159 @@
/*
* Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
*/
package com.baidu.ocr.ui.util;
import android.graphics.BitmapFactory;
import android.media.ExifInterface;
import android.util.Log;
public class ImageUtil {
private static final String TAG = "CameraExif";
public static int exifToDegrees(int exifOrientation) {
if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
return 90;
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
return 180;
} else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
return 270;
}
return 0;
}
// Returns the degrees in clockwise. Values are 0, 90, 180, or 270.
public static int getOrientation(byte[] jpeg) {
if (jpeg == null) {
return 0;
}
int offset = 0;
int length = 0;
// ISO/IEC 10918-1:1993(E)
while (offset + 3 < jpeg.length && (jpeg[offset++] & 0xFF) == 0xFF) {
int marker = jpeg[offset] & 0xFF;
// Check if the marker is a padding.
if (marker == 0xFF) {
continue;
}
offset++;
// Check if the marker is SOI or TEM.
if (marker == 0xD8 || marker == 0x01) {
continue;
}
// Check if the marker is EOI or SOS.
if (marker == 0xD9 || marker == 0xDA) {
break;
}
// Get the length and check if it is reasonable.
length = pack(jpeg, offset, 2, false);
if (length < 2 || offset + length > jpeg.length) {
Log.e(TAG, "Invalid length");
return 0;
}
// Break if the marker is EXIF in APP1.
if (marker == 0xE1 && length >= 8
&& pack(jpeg, offset + 2, 4, false) == 0x45786966
&& pack(jpeg, offset + 6, 2, false) == 0) {
offset += 8;
length -= 8;
break;
}
// Skip other markers.
offset += length;
length = 0;
}
// JEITA CP-3451 Exif Version 2.2
if (length > 8) {
// Identify the byte order.
int tag = pack(jpeg, offset, 4, false);
if (tag != 0x49492A00 && tag != 0x4D4D002A) {
Log.e(TAG, "Invalid byte order");
return 0;
}
boolean littleEndian = (tag == 0x49492A00);
// Get the offset and check if it is reasonable.
int count = pack(jpeg, offset + 4, 4, littleEndian) + 2;
if (count < 10 || count > length) {
Log.e(TAG, "Invalid offset");
return 0;
}
offset += count;
length -= count;
// Get the count and go through all the elements.
count = pack(jpeg, offset - 2, 2, littleEndian);
while (count-- > 0 && length >= 12) {
// Get the tag and check if it is orientation.
tag = pack(jpeg, offset, 2, littleEndian);
if (tag == 0x0112) {
// We do not really care about type and count, do we?
int orientation = pack(jpeg, offset + 8, 2, littleEndian);
switch (orientation) {
case 1:
return 0;
case 3:
return 180;
case 6:
return 90;
case 8:
return 270;
default:
return 0;
}
}
offset += 12;
length -= 12;
}
}
Log.i(TAG, "Orientation not found");
return 0;
}
private static int pack(byte[] bytes, int offset, int length,
boolean littleEndian) {
int step = 1;
if (littleEndian) {
offset += length - 1;
step = -1;
}
int value = 0;
while (length-- > 0) {
value = (value << 8) | (bytes[offset] & 0xFF);
offset += step;
}
return value;
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) >= reqHeight
&& (halfWidth / inSampleSize) >= reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 519 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#000000" />
<corners android:radius="12dp" />
</shape>
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 按压时 -->
<item android:drawable="@drawable/bd_ocr_take_photo_highlight" android:state_pressed="true" />
<!-- 被选中时 -->
<item android:drawable="@drawable/bd_ocr_take_photo_normal" android:state_selected="true" />
<!-- 被激活时 -->
<item android:drawable="@drawable/bd_ocr_take_photo_normal" android:state_activated="true" />
<!-- 默认时 -->
<item android:drawable="@drawable/bd_ocr_take_photo_normal" />
</selector>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
-->
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="@+id/take_picture_container"
android:layout_height="match_parent"
android:layout_width="match_parent"
layout="@layout/bd_ocr_take_picture"/>
<include
android:id="@+id/crop_container"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:visibility="gone"
layout="@layout/bd_ocr_crop"/>
<include
android:id="@+id/confirm_result_container"
layout="@layout/bd_ocr_confirm_result"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
-->
<com.baidu.ocr.ui.camera.OCRCameraLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentView="@+id/display_image_view"
app:leftDownView="@+id/cancel_button"
app:rightUpView="@+id/confirm_button">
<ImageView
android:id="@+id/display_image_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
app:srcCompat="@drawable/bd_ocr_id_card_locator_front"/>
<ImageView
android:id="@+id/cancel_button"
android:layout_width="60dp"
android:layout_height="40dp"
android:padding="12dp"
android:src="@drawable/bd_ocr_cancel"
android:layout_marginLeft="@dimen/camera_left_margin"
android:layout_marginStart="@dimen/camera_left_margin"
android:layout_marginBottom="@dimen/camera_bottom_margin"
/>
<ImageView
android:id="@+id/confirm_button"
android:layout_width="60dp"
android:layout_height="40dp"
android:padding="12dp"
android:src="@drawable/bd_ocr_confirm"
android:layout_marginRight="@dimen/camera_right_margin"
android:layout_marginEnd="@dimen/camera_right_margin"
android:layout_marginTop="@dimen/camera_top_margin"
/>
</com.baidu.ocr.ui.camera.OCRCameraLayout>
@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
-->
<com.baidu.ocr.ui.camera.OCRCameraLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentView="@+id/crop_view_container"
app:leftDownView="@+id/cancel_button"
app:centerView="@+id/rotate_button"
app:rightUpView="@+id/confirm_button">
<com.baidu.ocr.ui.camera.OCRFrameLayout
android:id="@+id/crop_view_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.baidu.ocr.ui.crop.CropView
android:id="@+id/crop_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.baidu.ocr.ui.crop.FrameOverlayView
android:id="@+id/overlay_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.baidu.ocr.ui.camera.MaskView
android:id="@+id/crop_mask_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</com.baidu.ocr.ui.camera.OCRFrameLayout>
<ImageView
android:id="@+id/rotate_button"
android:layout_width="60dp"
android:layout_height="58dp"
android:padding="18dp"
android:src="@drawable/bd_ocr_rotate"/>
<ImageView
android:id="@+id/confirm_button"
android:layout_width="60dp"
android:layout_height="40dp"
android:padding="12dp"
android:src="@drawable/bd_ocr_confirm"
android:layout_marginRight="@dimen/camera_right_margin"
android:layout_marginEnd="@dimen/camera_right_margin"
android:layout_marginTop="@dimen/camera_top_margin"/>
<ImageView
android:id="@+id/cancel_button"
android:layout_width="60dp"
android:layout_height="40dp"
android:padding="12dp"
android:src="@drawable/bd_ocr_cancel"
android:layout_marginLeft="@dimen/camera_left_margin"
android:layout_marginStart="@dimen/camera_left_margin"
android:layout_marginBottom="@dimen/camera_bottom_margin"/>
</com.baidu.ocr.ui.camera.OCRCameraLayout>
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
-->
<com.baidu.ocr.ui.camera.OCRCameraLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentView="@+id/camera_view"
app:leftDownView="@+id/album_button"
app:centerView="@+id/take_photo_button"
app:rightUpView="@+id/light_button">
<com.baidu.ocr.ui.camera.CameraView
android:id="@+id/camera_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.baidu.ocr.ui.camera.CameraView>
<ImageView
android:id="@+id/album_button"
android:layout_width="60dp"
android:layout_height="54dp"
android:padding="18dp"
android:layout_marginLeft="@dimen/camera_left_margin"
android:layout_marginStart="@dimen/camera_left_margin"
android:layout_marginBottom="@dimen/camera_bottom_margin"
android:src="@drawable/bd_ocr_gallery"/>
<ImageView
android:id="@+id/take_photo_button"
android:layout_width="58dp"
android:layout_height="58dp"
android:clickable="true"
android:background="@drawable/bd_ocr_take_photo_selector"/>
<ImageView
android:id="@+id/light_button"
android:layout_width="60dp"
android:layout_height="60dp"
android:padding="15dp"
android:clickable="true"
android:layout_marginRight="@dimen/camera_right_margin"
android:layout_marginEnd="@dimen/camera_right_margin"
android:layout_marginTop="@dimen/camera_top_margin"
android:paddingBottom="3dp"
android:src="@drawable/bd_ocr_light_off"
/>
</com.baidu.ocr.ui.camera.OCRCameraLayout>
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
-->
<resources>
<dimen name="camera_left_margin">18dp</dimen>
<dimen name="camera_right_margin">18dp</dimen>
<dimen name="camera_bottom_margin">16dp</dimen>
<dimen name="camera_top_margin">16dp</dimen>
</resources>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
-->
<resources>
<declare-styleable name="OCRCameraLayout">
<attr name="contentView" format="reference"/>
<attr name="centerView" format="reference"/>
<attr name="leftDownView" format="reference"/>
<attr name="rightUpView" format="reference"/>
</declare-styleable>
</resources>
+9
View File
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
-->
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
+7
View File
@@ -0,0 +1,7 @@
<!--
~ Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
-->
<resources>
<string name="app_name">OCR_UI</string>
<string name="camera_permission_required">本功能需要相机权限!</string>
</resources>
+14
View File
@@ -0,0 +1,14 @@
<!--
~ Copyright (C) 2017 Baidu, Inc. All Rights Reserved.
-->
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
+2
View File
@@ -6,3 +6,5 @@ include ':record'
//include ':ocr_ui' //include ':ocr_ui'
//include ':AliyunListPlayer' //include ':AliyunListPlayer'
include ':mylibrary' include ':mylibrary'
include ':ocr_ui'
include ':ocr_ui'