list, Context context){
33 | channelList = list;
34 | layoutInflater = LayoutInflater.from(context);
35 | }
36 |
37 | /**
38 | * 设置list的数目
39 | * @return 返回数目
40 | */
41 | @Override
42 | public int getCount() {
43 | return channelList.size();
44 | }
45 |
46 | @Override
47 | public Object getItem(int position) {
48 | return null;
49 | }
50 |
51 | @Override
52 | public long getItemId(int position) {
53 | return 0;
54 | }
55 |
56 | @SuppressLint("InflateParams")
57 | @Override
58 | public View getView(int position, View convertView, ViewGroup parent) {
59 | ViewHolder holder = null;
60 |
61 | // 把view放到布局里面缓存
62 | if(convertView == null){
63 | //加载布局
64 | convertView =layoutInflater.inflate(R.layout.item_grid,null);
65 | // 缓存布局
66 | holder = new ViewHolder();
67 | holder.imgChannel =convertView.findViewById(R.id.img);
68 | holder.decChannel =convertView.findViewById(R.id.dec);
69 | convertView.setTag(holder);
70 | }else{
71 | holder = (ViewHolder)convertView.getTag();
72 | }
73 |
74 | //设置图标和文字
75 | Channel channel = channelList.get(position);
76 | // 设置图标和文字
77 | if(channel != null){
78 | holder.decChannel.setText(channel.getDec());
79 | holder.imgChannel.setImageResource(channel.getImgId());
80 | }
81 | return convertView;
82 | }
83 |
84 | /**
85 | * view holder布局
86 | */
87 | static class ViewHolder{
88 | ImageView imgChannel;
89 | TextView decChannel;
90 | }
91 |
92 | // /**
93 | // *
94 | // */
95 | // interface OnItemClickListener{
96 | // void onClick(int posttion);
97 | // }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/common/Constants.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.common;
2 |
3 | public class Constants {
4 |
5 | public static final String APP_ID = "xxxxxx";
6 | public static final String SDK_KEY = "xxxxx";
7 |
8 | /**
9 | * IR预览数据相对于RGB预览数据的横向偏移量,注意:是预览数据,一般的摄像头的预览数据都是 width > height
10 | */
11 | public static final int HORIZONTAL_OFFSET = 0;
12 | /**
13 | * IR预览数据相对于RGB预览数据的纵向偏移量,注意:是预览数据,一般的摄像头的预览数据都是 width > height
14 | */
15 | public static final int VERTICAL_OFFSET = 0;
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/engine/GlideEngine.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.engine;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.net.Uri;
6 | import android.widget.ImageView;
7 |
8 | import androidx.annotation.NonNull;
9 |
10 | import com.bumptech.glide.Glide;
11 | import com.huantansheng.easyphotos.engine.ImageEngine;
12 |
13 | import static com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade;
14 |
15 | /**
16 | * 自定义图片引擎
17 | *
18 | * @author 小游
19 | * @date 2020/12/15
20 | */
21 | public class GlideEngine implements ImageEngine {
22 | //单例
23 | private static GlideEngine instance = null;
24 | //单例模式,私有构造方法
25 | private GlideEngine() {
26 | }
27 | //获取单例
28 | public static GlideEngine getInstance() {
29 | if (null == instance) {
30 | synchronized (GlideEngine.class) {
31 | if (null == instance) {
32 | instance = new GlideEngine();
33 | }
34 | }
35 | }
36 | return instance;
37 | }
38 |
39 | /**
40 | * 加载图片到ImageView
41 | *
42 | * @param context 上下文
43 | * @param uri 图片路径Uri
44 | * @param imageView 加载到的ImageView
45 | */
46 | //安卓10推荐uri,并且path的方式不再可用
47 | @Override
48 | public void loadPhoto(Context context, Uri uri, ImageView imageView) {
49 | Glide.with(context).load(uri).transition(withCrossFade()).into(imageView);
50 | }
51 |
52 | /**
53 | * 加载gif动图图片到ImageView,gif动图不动
54 | *
55 | * @param context 上下文
56 | * @param gifUri gif动图路径Uri
57 | * @param imageView 加载到的ImageView
58 | *
59 | * 备注:不支持动图显示的情况下可以不写
60 | */
61 | //安卓10推荐uri,并且path的方式不再可用
62 | @Override
63 | public void loadGifAsBitmap(Context context, Uri gifUri, ImageView imageView) {
64 | Glide.with(context).asBitmap().load(gifUri).into(imageView);
65 | }
66 |
67 | /**
68 | * 加载gif动图到ImageView,gif动图动
69 | *
70 | * @param context 上下文
71 | * @param gifUri gif动图路径Uri
72 | * @param imageView 加载动图的ImageView
73 | *
74 | * 备注:不支持动图显示的情况下可以不写
75 | */
76 | //安卓10推荐uri,并且path的方式不再可用
77 | @Override
78 | public void loadGif(Context context, Uri gifUri, ImageView imageView) {
79 | Glide.with(context).asGif().load(gifUri).transition(withCrossFade()).into(imageView);
80 | }
81 |
82 |
83 | /**
84 | * 获取图片加载框架中的缓存Bitmap
85 | *
86 | * @param context 上下文
87 | * @param uri 图片路径
88 | * @param width 图片宽度
89 | * @param height 图片高度
90 | * @return Bitmap
91 | * @throws Exception 异常直接抛出,EasyPhotos内部处理
92 | */
93 | //安卓10推荐uri,并且path的方式不再可用
94 | @Override
95 | public Bitmap getCacheBitmap(Context context, Uri uri, int width, int height) throws Exception {
96 | return Glide.with(context).asBitmap().load(uri).submit(width, height).get();
97 | }
98 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/faceserver/CompareResult.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.faceserver;
2 |
3 |
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | /**
9 | * 比对结果
10 | * @author 小游
11 | * @date 2020/12/16
12 | */
13 | @Data
14 | @AllArgsConstructor
15 | @NoArgsConstructor
16 | public class CompareResult {
17 | /**
18 | * id
19 | */
20 | private String id;
21 | /**
22 | * 姓名
23 | */
24 | private String userName;
25 | /**
26 | * 学号
27 | */
28 | private String userNo;
29 | /**
30 | * 相似度
31 | */
32 | private float similar;
33 | /**
34 | * 追踪id
35 | */
36 | private int trackId;
37 |
38 | public CompareResult(String id,String stuId,String name, float similar) {
39 | this.id = id;
40 | this.userNo =stuId;
41 | this.userName =name;
42 | this.similar = similar;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/fragment/IndexFragment.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.fragment;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 |
7 | import androidx.fragment.app.Fragment;
8 |
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.RelativeLayout;
13 | import android.widget.TextView;
14 |
15 | import com.haibin.calendarview.Calendar;
16 | import com.haibin.calendarview.CalendarLayout;
17 | import com.haibin.calendarview.CalendarView;
18 | import com.xiaoyou.face.R;
19 | import com.xiaoyou.face.activity.RegisterAndRecognizeActivity;
20 | import com.xiaoyou.face.activity.SignDetailActivity;
21 | import com.xiaoyou.face.adapter.FunctionAdapter;
22 | import com.xiaoyou.face.databinding.FragmentIndexBinding;
23 | import com.xiaoyou.face.model.Channel;
24 | import com.xiaoyou.face.service.DateHistoryTO;
25 | import com.xiaoyou.face.service.SQLiteHelper;
26 | import com.xiaoyou.face.service.Service;
27 | import com.xiaoyou.face.utils.Tools;
28 |
29 | import java.util.ArrayList;
30 | import java.util.HashMap;
31 | import java.util.List;
32 | import java.util.Map;
33 |
34 | /**
35 | * 打卡的fragment类
36 | * @author 小游
37 | * @date 2020/12/14
38 | */
39 | public class IndexFragment extends Fragment implements
40 | CalendarView.OnCalendarSelectListener,
41 | CalendarView.OnYearChangeListener,
42 | View.OnClickListener{
43 |
44 | /**
45 | * 日历组件显示的时间map值
46 | */
47 | Map timeMap;
48 |
49 | private FragmentIndexBinding binding;
50 | TextView mTextMonthDay;
51 | TextView mTextYear;
52 | TextView mTextLunar;
53 | TextView mTextCurrentDay;
54 | CalendarView mCalendarView;
55 | RelativeLayout mRelativeTool;
56 | private int mYear;
57 | CalendarLayout mCalendarLayout;
58 |
59 | private final static int REQUEST_CODE = 45;
60 |
61 |
62 | @Override
63 | public void onCreate(Bundle savedInstanceState) {
64 | super.onCreate(savedInstanceState);
65 | }
66 |
67 | @Override
68 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
69 | // 这里我们使用bindview 来进行视图绑定
70 | binding = FragmentIndexBinding.inflate(inflater, container, false);
71 | // 我们这里给控件赋值
72 | // 月份显示
73 | mTextMonthDay = binding.tvMonthDay;
74 | // 年份显示
75 | mTextYear = binding.tvYear;
76 | // 时间显示
77 | mTextLunar = binding.tvLunar;
78 | // 现在时间
79 | mTextCurrentDay = binding.tvCurrentDay;
80 | // 日历视图组件
81 | mCalendarView = binding.calendarView;
82 | // 时间显示控件
83 | mRelativeTool = binding.rlTool;
84 | // 日历布局
85 | mCalendarLayout = binding.calendarLayout;
86 | // 数据初始化
87 | initView();
88 | initData();
89 | // 宫格布局初始化
90 | // 9宫格布局初始化
91 | ArrayList channelList = new ArrayList<>();
92 | channelList.add(new Channel(R.mipmap.face,"人脸录入"));
93 | channelList.add(new Channel(R.mipmap.login,"开始签到"));
94 | channelList.add(new Channel(R.mipmap.statistics,"签到详情"));
95 | binding.toolList.setAdapter(new FunctionAdapter(channelList,getContext()));
96 | // grad 布局点击事件监听
97 | binding.toolList.setOnItemClickListener((parent, view, position, id) -> {
98 | switch (position){
99 | case 0:
100 | startActivity(new Intent(getContext(), RegisterAndRecognizeActivity.class));
101 | break;
102 | case 1:
103 | // 签到不需要显示录入按钮
104 | Intent intent = new Intent(getContext(), RegisterAndRecognizeActivity.class);
105 | intent.putExtra("login",false);
106 | startActivity(intent);
107 | break;
108 | case 2:
109 | startActivity(new Intent(getContext(), SignDetailActivity.class));
110 | break;
111 | default:
112 | break;
113 | }
114 | });
115 | // 返回视图view
116 | return binding.getRoot();
117 | }
118 |
119 | @Override
120 | public void onClick(View v) {
121 |
122 | }
123 |
124 | @Override
125 | public void onCalendarOutOfRange(Calendar calendar) {
126 |
127 | }
128 |
129 | /**
130 | * 日历视图点击事件
131 | * @param calendar 日历控件
132 | * @param isClick 是否点击
133 | */
134 | @SuppressLint("SetTextI18n")
135 | @Override
136 | public void onCalendarSelect(Calendar calendar, boolean isClick) {
137 | // 显示时间控件
138 | mTextLunar.setVisibility(View.VISIBLE);
139 | mTextYear.setVisibility(View.VISIBLE);
140 |
141 | // 我们这里修改导航栏的时间显示
142 | mTextMonthDay.setText(calendar.getMonth() + "月" + calendar.getDay() + "日");
143 | mTextYear.setText(String.valueOf(calendar.getYear()));
144 | mTextLunar.setText(calendar.getLunar());
145 | mYear = calendar.getYear();
146 | }
147 |
148 | @Override
149 | public void onYearChange(int year) {
150 | // 年份视图点击的时候修改顶部的时间
151 | mTextMonthDay.setText(String.valueOf(year));
152 | }
153 |
154 | /**
155 | * 设置标记
156 | * @param year 年份
157 | * @param month 月份
158 | * @param day 日
159 | * @param color 颜色
160 | * @return calendar对象
161 | */
162 | private Calendar getSchemeCalendar(int year, int month, int day, int color) {
163 | Calendar calendar = new Calendar();
164 | calendar.setYear(year);
165 | calendar.setMonth(month);
166 | calendar.setDay(day);
167 | // 如果单独标记颜色、则会使用这个颜色
168 | calendar.setSchemeColor(color);
169 | return calendar;
170 | }
171 |
172 |
173 | /**
174 | * 视图初始化
175 | */
176 | @SuppressLint("SetTextI18n")
177 | protected void initView() {
178 | // 点击月份显示月份切换
179 | mTextMonthDay.setOnClickListener(v -> {
180 | if (!mCalendarLayout.isExpand()) {
181 | mCalendarLayout.expand();
182 | return;
183 | }
184 | // 显示月份
185 | mCalendarView.showYearSelectLayout(mYear);
186 | // 隐藏隐藏年份和时间
187 | mTextLunar.setVisibility(View.GONE);
188 | mTextYear.setVisibility(View.GONE);
189 | // 月份哪里显示时间
190 | mTextMonthDay.setText(String.valueOf(mYear));
191 | });
192 | // 点击今天就直接跳转到今天
193 | binding.flCurrent.setOnClickListener(v -> mCalendarView.scrollToCurrent());
194 |
195 | // 日历点击事件(包括年份点击)
196 | mCalendarView.setOnCalendarSelectListener(this);
197 | mCalendarView.setOnYearChangeListener(this);
198 |
199 | // 这里我们显示当前时间到顶部导航栏
200 | mTextYear.setText(String.valueOf(mCalendarView.getCurYear()));
201 | mYear = mCalendarView.getCurYear();
202 | mTextMonthDay.setText(mCalendarView.getCurMonth() + "月" + mCalendarView.getCurDay() + "日");
203 | mTextLunar.setText("今日");
204 | // 显示今天日期
205 | mTextCurrentDay.setText(String.valueOf(mCalendarView.getCurDay()));
206 | }
207 |
208 |
209 | /**
210 | * 日历初始化
211 | */
212 | private void initData(){
213 | // int year = mCalendarView.getCurYear();
214 | // int month = mCalendarView.getCurMonth();
215 | Service service = new SQLiteHelper(getContext());
216 | List calendar = service.getCalendar();
217 | timeMap = new HashMap<>();
218 | // 添加时间标记
219 | for (DateHistoryTO history : calendar) {
220 | addMark(history.getYear(),history.getMonth(),history.getDay());
221 | }
222 | //此方法在巨大的数据量上不影响遍历性能,推荐使用
223 | mCalendarView.setSchemeDate(timeMap);
224 | }
225 |
226 | /**
227 | * 添加时间标记
228 | */
229 | private void addMark(int year, int month, int day){
230 | timeMap.put(getSchemeCalendar(year, month, day, Tools.getRandomColor()).toString(),
231 | getSchemeCalendar(year, month, day, Tools.getRandomColor()));
232 | }
233 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/fragment/MeFragment.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.fragment;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.os.Bundle;
6 |
7 | import androidx.core.content.ContextCompat;
8 | import androidx.fragment.app.Fragment;
9 |
10 | import android.util.Log;
11 | import android.view.KeyEvent;
12 | import android.view.LayoutInflater;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.view.inputmethod.InputMethodManager;
16 | import android.widget.TextView;
17 |
18 | import com.bin.david.form.data.CellInfo;
19 | import com.bin.david.form.data.format.bg.BaseCellBackgroundFormat;
20 | import com.bin.david.form.data.style.FontStyle;
21 | import com.xiaoyou.face.R;
22 | import com.xiaoyou.face.databinding.FragmentMeBinding;
23 | import com.xiaoyou.face.model.Login;
24 | import com.xiaoyou.face.service.SQLiteHelper;
25 | import com.xiaoyou.face.service.Service;
26 | import com.xiaoyou.face.service.StudentInfoTO;
27 | import com.xiaoyou.face.utils.ToastUtils;
28 | import com.xiaoyou.face.utils.Tools;
29 |
30 | import java.text.ParseException;
31 | import java.text.SimpleDateFormat;
32 | import java.util.ArrayList;
33 | import java.util.List;
34 | import java.util.Objects;
35 |
36 | /**
37 | * 查询界面
38 | * @author 小游
39 | */
40 | public class MeFragment extends Fragment {
41 |
42 | private FragmentMeBinding binding;
43 |
44 | @Override
45 | public void onCreate(Bundle savedInstanceState) {
46 | super.onCreate(savedInstanceState);
47 | }
48 |
49 | @Override
50 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
51 | Bundle savedInstanceState) {
52 | // 这里我们使用bindview 来进行视图绑定
53 | binding = FragmentMeBinding.inflate(inflater, container, false);
54 | initView();
55 | // 返回视图view
56 | return binding.getRoot();
57 | }
58 |
59 | /**
60 | * 视图初始化
61 | */
62 | private void initView(){
63 | // 表格样式(占满全屏)
64 | binding.table.getConfig().setMinTableWidth(Tools.getWidth(getContext()));
65 | // 搜索按钮点击事件
66 | binding.search.setOnClickListener(v->{
67 | search();
68 | });
69 | // 编辑框回车事件
70 | binding.editKey.setOnEditorActionListener((v, actionId, event) -> {
71 | search();
72 | return true;
73 | });
74 | }
75 |
76 | /**
77 | * 搜索
78 | */
79 | private void search(){
80 | int type = binding.searchType.getSelectedIndex();
81 | String key =binding.editKey.getEditValue();
82 | // 自动隐藏键盘
83 | InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
84 | assert imm != null;
85 | imm.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
86 | // 初始化数据库查找
87 | Service service = new SQLiteHelper(getContext());
88 | List list = new ArrayList<>();
89 | try {
90 | // 从数据库中获取数据
91 | list = service.queryStudentInfo(type==0?key:"", type==1?key:"");
92 | } catch (ParseException e) {
93 | e.printStackTrace();
94 | }
95 | List lists = new ArrayList<>();
96 | @SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
97 | for (StudentInfoTO studentInfo : list) {
98 | lists.add(new Login(studentInfo.getStuId(),studentInfo.getName(),sdf.format(studentInfo.getDateTime())));
99 | }
100 | // 表格显示数据
101 | showDetail(lists);
102 | }
103 |
104 |
105 | /**
106 | * 显示签到的详情情况
107 | */
108 | private void showDetail(List list){
109 | // 显示数据
110 | binding.table.setData(list);
111 | // 统计行
112 | binding.table.getConfig().setFixedTitle(true);
113 | // 格式化内容背景(这里我们设置背景交替)
114 | binding.table.getConfig().setContentCellBackgroundFormat(new BaseCellBackgroundFormat() {
115 | @Override
116 | public int getBackGroundColor(CellInfo cellInfo) {
117 | int color = R.color.white;
118 | if (cellInfo.row%2 ==0){
119 | color = R.color.tab_background;
120 | }
121 | return ContextCompat.getColor(Objects.requireNonNull(getContext()), color);
122 | }
123 | });
124 | // 隐藏顶部的序号列
125 | binding.table.getConfig().setShowXSequence(false);
126 | }
127 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/fragment/ToolFragment.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.fragment;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.graphics.Color;
5 | import android.graphics.Typeface;
6 | import android.os.Bundle;
7 |
8 | import androidx.fragment.app.Fragment;
9 |
10 | import android.util.Log;
11 | import android.view.LayoutInflater;
12 | import android.view.View;
13 | import android.view.ViewGroup;
14 |
15 | import com.github.mikephil.charting.animation.Easing;
16 | import com.github.mikephil.charting.charts.BarChart;
17 | import com.github.mikephil.charting.charts.PieChart;
18 | import com.github.mikephil.charting.components.Legend;
19 | import com.github.mikephil.charting.components.XAxis;
20 | import com.github.mikephil.charting.components.YAxis;
21 | import com.github.mikephil.charting.data.BarData;
22 | import com.github.mikephil.charting.data.BarDataSet;
23 | import com.github.mikephil.charting.data.BarEntry;
24 | import com.github.mikephil.charting.data.PieData;
25 | import com.github.mikephil.charting.data.PieDataSet;
26 | import com.github.mikephil.charting.data.PieEntry;
27 | import com.github.mikephil.charting.formatter.ValueFormatter;
28 | import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
29 | import com.xiaoyou.face.databinding.FragmentToolBinding;
30 | import com.xiaoyou.face.service.DateHistoryTO;
31 | import com.xiaoyou.face.service.History;
32 | import com.xiaoyou.face.service.SQLiteHelper;
33 | import com.xiaoyou.face.service.Service;
34 | import com.xuexiang.xui.widget.textview.supertextview.SuperButton;
35 |
36 | import java.text.SimpleDateFormat;
37 | import java.util.ArrayList;
38 | import java.util.List;
39 |
40 |
41 | /**
42 | * 工具界面点击效果
43 | * @author 小游
44 | */
45 | public class ToolFragment extends Fragment {
46 | private FragmentToolBinding binding;
47 |
48 | @Override
49 | public void onCreate(Bundle savedInstanceState) {
50 | super.onCreate(savedInstanceState);
51 | }
52 |
53 | @Override
54 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
55 | // 这里我们使用bindview 来进行视图绑定
56 | binding = FragmentToolBinding.inflate(inflater, container, false);
57 | initView();
58 | // 返回视图view
59 | return binding.getRoot();
60 | }
61 |
62 | /**
63 | * 视图初始化
64 | */
65 | private void initView(){
66 | // 指示器绑定
67 | binding.functionChoose.setTabTitles(new String[]{"考勤情况统计","考勤历史"});
68 | // 指示器点击事件
69 | binding.functionChoose.setOnTabClickListener(((title, position) -> {
70 | switch (position){
71 | case 0:
72 | showRingPieChart();
73 | break;
74 | case 1:
75 | showAttendanceHistory();
76 | break;
77 | default:
78 | break;
79 | }
80 | }));
81 | // 显示考勤情况统计
82 | showRingPieChart();
83 | }
84 |
85 | /**
86 | * 显示考勤情况统计
87 | */
88 | private void showRingPieChart() {
89 | binding.flContainer.setVisibility(View.VISIBLE);
90 | binding.linearContainer.setVisibility(View.INVISIBLE);
91 | // 设置每份所占数量
92 | List yvals = new ArrayList<>();
93 | // 获取签到记录
94 | Service service = new SQLiteHelper(getContext());
95 | History history = service.getTodayHistory();
96 |
97 | yvals.add(new PieEntry(history.getIsSignUp(), "已签到"));
98 | yvals.add(new PieEntry(history.getNotSigUp(), "未签到"));
99 | //设置每份的颜色
100 | List colors = new ArrayList<>();
101 | colors.add(Color.parseColor("#409EFF"));
102 | colors.add(Color.parseColor("#F56C6C"));
103 | // 图表初始化
104 | PieChart pieChart = binding.flContainer;
105 | // 是否显示中间的洞
106 | pieChart.setDrawHoleEnabled(true);
107 | //设置中间洞的大小
108 | pieChart.setHoleRadius(30f);
109 |
110 | // 半透明圈
111 | pieChart.setTransparentCircleRadius(35f);
112 | //设置半透明圆圈的颜色
113 | pieChart.setTransparentCircleColor(Color.WHITE);
114 | //设置半透明圆圈的透明度
115 | pieChart.setTransparentCircleAlpha(125);
116 |
117 |
118 | //饼状图中间可以添加文字
119 | pieChart.setDrawCenterText(true);
120 | //设置中间文字
121 | pieChart.setCenterText("签到情况统计");
122 | //中间问题的颜色
123 | pieChart.setCenterTextColor(Color.parseColor("#a1a1a1"));
124 | //中间文字的大小px
125 | pieChart.setCenterTextSizePixels(25);
126 | pieChart.setCenterTextRadiusPercent(1f);
127 | //中间文字的样式
128 | pieChart.setCenterTextTypeface(Typeface.DEFAULT);
129 | //中间文字的偏移量
130 | pieChart.setCenterTextOffset(0, 0);
131 |
132 | // 初始旋转角度
133 | pieChart.setRotationAngle(0);
134 | // 可以手动旋转
135 | pieChart.setRotationEnabled(true);
136 | //显示成百分比
137 | pieChart.setUsePercentValues(true);
138 | //取消右下角描述
139 | pieChart.getDescription().setEnabled(false);
140 |
141 | //是否显示每个部分的文字描述
142 | pieChart.setDrawEntryLabels(true);
143 | //描述文字的颜色
144 | pieChart.setEntryLabelColor(Color.WHITE);
145 | //描述文字的大小
146 | pieChart.setEntryLabelTextSize(14);
147 | //描述文字的样式
148 | pieChart.setEntryLabelTypeface(Typeface.DEFAULT_BOLD);
149 |
150 | //图相对于上下左右的偏移
151 | pieChart.setExtraOffsets(20, 0, 20, 8);
152 | //图标的背景色
153 | pieChart.setBackgroundColor(Color.TRANSPARENT);
154 | // 设置pieChart图表转动阻力摩擦系数[0,1]
155 | pieChart.setDragDecelerationFrictionCoef(0.75f);
156 |
157 | //获取图例
158 | Legend legend = pieChart.getLegend();
159 | //设置图例水平显示
160 | legend.setOrientation(Legend.LegendOrientation.VERTICAL);
161 | //顶部
162 | legend.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);
163 | //右对其
164 | legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.RIGHT);
165 |
166 | //x轴的间距
167 | legend.setXEntrySpace(7f);
168 | //y轴的间距
169 | legend.setYEntrySpace(10f);
170 | //图例的y偏移量
171 | legend.setYOffset(10f);
172 | //图例x的偏移量
173 | legend.setXOffset(10f);
174 | //图例文字的颜色
175 | legend.setTextColor(Color.parseColor("#a1a1a1"));
176 | //图例文字的大小
177 | legend.setTextSize(13);
178 |
179 | //数据集合
180 | PieDataSet dataset = new PieDataSet(yvals, "");
181 | //填充每个区域的颜色
182 | dataset.setColors(colors);
183 | //是否在图上显示数值
184 | dataset.setDrawValues(true);
185 | // 文字的大小
186 | dataset.setValueTextSize(14);
187 | // 文字的颜色
188 | dataset.setValueTextColor(Color.parseColor("#3498db"));
189 | //文字的样式
190 | dataset.setValueTypeface(Typeface.DEFAULT_BOLD);
191 |
192 | // 当值位置为外边线时,表示线的前半段长度。
193 | dataset.setValueLinePart1Length(0.4f);
194 | // 当值位置为外边线时,表示线的后半段长度。
195 | dataset.setValueLinePart2Length(0.4f);
196 | // 当ValuePosits为OutsiDice时,指示偏移为切片大小的百分比
197 | dataset.setValueLinePart1OffsetPercentage(80f);
198 | // 当值位置为外边线时,表示线的颜色。
199 | dataset.setValueLineColor(Color.parseColor("#a1a1a1"));
200 | // 设置Y值的位置是在圆内还是圆外
201 | dataset.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
202 | // 设置Y轴描述线和填充区域的颜色一致
203 | dataset.setUsingSliceColorAsValueLineColor(true);
204 | // 设置每条之前的间隙
205 | dataset.setSliceSpace(0);
206 |
207 | //设置饼状Item被选中时变化的距离
208 | dataset.setSelectionShift(5f);
209 | //填充数据
210 | PieData pieData = new PieData(dataset);
211 | // 格式化显示的数据为%百分比
212 | pieChart.setUsePercentValues(false);
213 | // 显示图表
214 | pieChart.setData(pieData);
215 | // 显示动画效果
216 | pieChart.animateY(500, Easing.EaseInOutQuad);
217 | }
218 |
219 | /**
220 | * 显示考勤历史
221 | */
222 | private void showAttendanceHistory(){
223 | // 设置控件显示
224 | binding.flContainer.setVisibility(View.INVISIBLE);
225 | binding.linearContainer.setVisibility(View.VISIBLE);
226 | //寻找到控件
227 | BarChart attendanceChart = binding.linearContainer;
228 |
229 | // 图例顶部显示
230 |
231 | //获取图例
232 | Legend legend = attendanceChart.getLegend();
233 | //设置图例水平显示
234 | legend.setOrientation(Legend.LegendOrientation.VERTICAL);
235 | //顶部
236 | legend.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);
237 | //右对其
238 | legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.RIGHT);
239 |
240 | // 不显示描述
241 | attendanceChart.getDescription().setEnabled(false);
242 | //y轴右边关闭
243 | YAxis leftAxis = attendanceChart.getAxisLeft();
244 | // 从零开始
245 | leftAxis.setAxisMinimum(0f);
246 | attendanceChart.getAxisRight().setEnabled(false);
247 | //x轴设置无网格
248 | XAxis xAxis = attendanceChart.getXAxis();
249 | xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
250 | xAxis.setDrawGridLines(false);
251 | // 获取考勤历史
252 | Service service = new SQLiteHelper(getContext());
253 | List histories = service.getHistory();
254 |
255 | // 设置x做显示
256 | ArrayList data2 = new ArrayList<>();
257 | for (DateHistoryTO history : histories) {
258 | data2.add(history.getMonth()+"-"+history.getDay());
259 | }
260 | xAxis.setValueFormatter(new ValueFormatter() {
261 | @Override
262 | public String getFormattedValue(float value) {
263 | return data2.get((int) value);
264 | }
265 | });
266 | //在放大到为轴设置的小数位数不再允许在两个轴值之间进行区分的点时,可以使用此方法来避免值重复。
267 | //创建两个数据集
268 | xAxis.setGranularity(1f);
269 | //数据集1
270 | List valsComp1 = new ArrayList();
271 | for(int i=0; i< histories.size();i++){
272 | valsComp1.add(new BarEntry(i,new float[] { histories.get(i).getIsSign(), histories.get(i).getUnSign()}));
273 | }
274 |
275 | //创建条形图对象
276 | BarDataSet setComp1 = new BarDataSet(valsComp1, "");
277 | setComp1.setDrawIcons(false);
278 | setComp1.setColors(Color.parseColor("#67c23a"),Color.parseColor("#f56c6c"));
279 | setComp1.setStackLabels(new String[]{"已签到", "未签到"});
280 | ArrayList dataSets = new ArrayList<>();
281 | dataSets.add(setComp1);
282 | //显示
283 | BarData data = new BarData(dataSets);
284 | attendanceChart.setData(data);
285 | attendanceChart.setFitBars(true);
286 | attendanceChart.invalidate();
287 | //设置动画样式
288 | attendanceChart.animateY(2000,Easing. EaseInOutQuad);
289 | }
290 |
291 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/model/Channel.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.model;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 |
6 | /**
7 | * 宫格布局内容
8 | * @author 小游
9 | * @date 2020/12/15
10 | */
11 | @Data
12 | @AllArgsConstructor
13 | public class Channel {
14 | private int imgId;
15 |
16 | private String dec;
17 | }
18 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/model/DrawInfo.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.model;
2 |
3 | import android.graphics.Rect;
4 |
5 | /**
6 | * 画笔信息
7 | * @author 小游
8 | */
9 | public class DrawInfo {
10 | private Rect rect;
11 | private int sex;
12 | private int age;
13 | private int liveness;
14 | private int color;
15 | private String name = null;
16 |
17 | public DrawInfo(Rect rect, int sex, int age, int liveness, int color, String name) {
18 | this.rect = rect;
19 | this.sex = sex;
20 | this.age = age;
21 | this.liveness = liveness;
22 | this.color = color;
23 | this.name = name;
24 | }
25 |
26 | public String getName() {
27 | return name;
28 | }
29 |
30 | public void setName(String name) {
31 | this.name = name;
32 | }
33 |
34 | public Rect getRect() {
35 | return rect;
36 | }
37 |
38 | public void setRect(Rect rect) {
39 | this.rect = rect;
40 | }
41 |
42 | public int getSex() {
43 | return sex;
44 | }
45 |
46 | public void setSex(int sex) {
47 | this.sex = sex;
48 | }
49 |
50 | public int getAge() {
51 | return age;
52 | }
53 |
54 | public void setAge(int age) {
55 | this.age = age;
56 | }
57 |
58 | public int getLiveness() {
59 | return liveness;
60 | }
61 |
62 | public void setLiveness(int liveness) {
63 | this.liveness = liveness;
64 | }
65 |
66 | public int getColor() {
67 | return color;
68 | }
69 |
70 | public void setColor(int color) {
71 | this.color = color;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/model/FacePreviewInfo.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.model;
2 |
3 | import com.arcsoft.face.FaceInfo;
4 |
5 | public class FacePreviewInfo {
6 | private FaceInfo faceInfo;
7 | private int trackId;
8 |
9 | public FacePreviewInfo(FaceInfo faceInfo, int trackId) {
10 | this.faceInfo = faceInfo;
11 | this.trackId = trackId;
12 | }
13 |
14 | public FaceInfo getFaceInfo() {
15 | return faceInfo;
16 | }
17 |
18 | public void setFaceInfo(FaceInfo faceInfo) {
19 | this.faceInfo = faceInfo;
20 | }
21 |
22 |
23 | public int getTrackId() {
24 | return trackId;
25 | }
26 |
27 | public void setTrackId(int trackId) {
28 | this.trackId = trackId;
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/model/FaceRegisterInfo.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.model;
2 |
3 | /**
4 | * 之前注册的人脸信息
5 | * @author 小游
6 | */
7 | public class FaceRegisterInfo {
8 | private byte[] featureData;
9 | private String name;
10 |
11 | public FaceRegisterInfo(byte[] faceFeature, String name) {
12 | this.featureData = faceFeature;
13 | this.name = name;
14 | }
15 |
16 | public String getName() {
17 | return name;
18 | }
19 |
20 | public void setName(String name) {
21 | this.name = name;
22 | }
23 |
24 | public byte[] getFeatureData() {
25 | return featureData;
26 | }
27 |
28 | public void setFeatureData(byte[] featureData) {
29 | this.featureData = featureData;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/model/Login.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.model;
2 |
3 | import com.bin.david.form.annotation.SmartColumn;
4 | import com.bin.david.form.annotation.SmartTable;
5 |
6 | import lombok.AllArgsConstructor;
7 | import lombok.Data;
8 |
9 | /**
10 | * 用户签到信息
11 | * @author 小游
12 | * @date 2020/12/16
13 | */
14 | @Data
15 | @AllArgsConstructor
16 | @SmartTable()
17 | public class Login {
18 | @SmartColumn(id =1,name = "学号")
19 | String no;
20 | @SmartColumn(id =2,name = "姓名")
21 | String name;
22 | @SmartColumn(id =3,name = "签到时间")
23 | String time;
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/service/DateFormatUtils.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.service;
2 |
3 | import android.os.Build;
4 |
5 | import androidx.annotation.RequiresApi;
6 |
7 | import java.time.LocalDateTime;
8 | import java.time.format.DateTimeFormatter;
9 | import java.util.Date;
10 |
11 | /**
12 | * @author lenyuqin
13 | * @data 2020/12/18
14 | */
15 | public class DateFormatUtils {
16 |
17 |
18 | /**
19 | *
20 | * @return 返回当前时间的字符串
21 | */
22 | @RequiresApi(api = Build.VERSION_CODES.O)
23 | public static String getTodayDate() {
24 | LocalDateTime time = LocalDateTime.now();
25 | DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
26 | return dateTimeFormatter.format(time);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/service/DateHistoryTO.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.service;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | /**
8 | * @author lenyuqin
9 | * @data 2020/12/19
10 | */
11 | @Data
12 | @AllArgsConstructor
13 | @NoArgsConstructor
14 | public class DateHistoryTO {
15 | private int year;
16 | private int day;
17 | private int month;
18 | private int isSign;
19 | private int unSign;
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/service/History.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.service;
2 |
3 | import java.time.LocalDate;
4 | import java.time.LocalDateTime;
5 |
6 | import lombok.AllArgsConstructor;
7 | import lombok.Data;
8 | import lombok.NoArgsConstructor;
9 |
10 | /**
11 | * @author lenyuqin
12 | * @data 2020/12/18
13 | */
14 | @Data
15 | @AllArgsConstructor
16 | @NoArgsConstructor
17 | public class History {
18 | private LocalDate date;
19 | private int isSignUp;
20 | private int notSigUp;
21 | }
22 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/service/Is_Sign.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.service;
2 |
3 | import lombok.Getter;
4 |
5 | /**
6 | * @author lenyuqin
7 | * @data 2020/12/16
8 | */
9 | @Getter
10 | public enum Is_Sign {
11 | //打卡成功
12 | TURE(1),
13 | //打卡失败
14 | FALSE(0);
15 |
16 | private final Integer code;
17 |
18 |
19 | Is_Sign(Integer code) {
20 | this.code = code;
21 | }
22 |
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/service/RegisterInfo.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.service;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | /**
8 | * 注册
9 | * @author 小游
10 | * @date 2020/12/16
11 | */
12 | @Data
13 | @AllArgsConstructor
14 | @NoArgsConstructor
15 | public class RegisterInfo {
16 | private int id;
17 | private String stuId;
18 | private String name;
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/service/SQLiteHelper.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.service;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.ContentValues;
5 | import android.content.Context;
6 | import android.database.Cursor;
7 | import android.database.sqlite.SQLiteDatabase;
8 | import android.database.sqlite.SQLiteOpenHelper;
9 | import android.os.Build;
10 | import android.util.Log;
11 |
12 | import androidx.annotation.RequiresApi;
13 |
14 | import java.text.ParseException;
15 | import java.text.SimpleDateFormat;
16 | import java.time.LocalDate;
17 | import java.time.LocalDateTime;
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | /**
22 | * @author lenyuqin
23 | * @data 2020/12/16
24 | */
25 | public class SQLiteHelper extends SQLiteOpenHelper implements Service {
26 | private final static String DATABASE_NAME = "FaceCheck";
27 | private final static int DATABASE_VERSION = 1;
28 | private final static String TABLE_ATTENDANCE = "attendance";
29 | private final static String TABLE_STUDENT = "student";
30 |
31 | //创建数据库,里面添加了3个参数,分别是:Msgone VARCHAR类型,30长度当然这了可以自定义
32 | //Msgtwo VARCHAR(20) Msgthree VARCHAR(30)) NOT NULL不能为空
33 | String sql = "CREATE TABLE attendance (stu_id int(11) NOT NULL ," +
34 | " name varchar(20) DEFAULT NULL ," +
35 | " is_Sign bit(1) DEFAULT NULL ," +
36 | " day int(5) DEFAULT NULL ," +
37 | " date date DEFAULT NULL ," +
38 | " month int(5) DEFAULT NULL ," +
39 | " year int(5) DEFAULT NULL)";
40 |
41 | String createStudent = "CREATE TABLE student (" +
42 | " id int(11) NOT NULL," +
43 | " stu_id varchar(20) NOT NULL," +
44 | " name varchar(20) DEFAULT NULL," +
45 | " PRIMARY KEY (id))";
46 |
47 | //构造函数,创建数据库
48 | public SQLiteHelper(Context context) {
49 | super(context, DATABASE_NAME, null, DATABASE_VERSION);
50 | }
51 |
52 |
53 | //建表
54 | @Override
55 | public void onCreate(SQLiteDatabase db) {
56 | db.execSQL(sql);
57 | db.execSQL(createStudent);
58 | }
59 |
60 | @Override
61 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
62 | String sql = "DROP TABLE IF EXISTS " + TABLE_ATTENDANCE;
63 | String sql2 = "DROP TABLE IF EXISTS " + TABLE_STUDENT;
64 | db.execSQL(sql);
65 | db.execSQL(sql2);
66 | onCreate(db);
67 | }
68 |
69 |
70 | //查询本月的数据,查询一个字段,返回日子的int集合 根据月去查询去除相同日子,返回日子
71 | @RequiresApi(api = Build.VERSION_CODES.O)
72 | public List queryByMouth() {
73 | SQLiteDatabase db = this.getReadableDatabase();
74 | String[] selectionArgs = new String[1];
75 | selectionArgs[1] = String.valueOf(LocalDate.now().getMonthValue());
76 | Cursor cursor = db.rawQuery("SELECT DISTINCT day FROM " + TABLE_ATTENDANCE + " WHERE month = ?", selectionArgs);
77 | ArrayList result = new ArrayList<>();
78 | while (cursor.isLast()) {
79 | String columnName = cursor.getColumnName(1);
80 | result.add(Integer.valueOf(columnName));
81 | cursor.moveToNext();
82 | }
83 | return result;
84 | }
85 |
86 |
87 | /**
88 | * 学生注册
89 | *
90 | * @param registerInfo 学生注册信息
91 | * @return 插入条数
92 | */
93 | @Override
94 | @RequiresApi(api = Build.VERSION_CODES.O)
95 | public long studentRegister(RegisterInfo registerInfo) {
96 | SQLiteDatabase db = this.getWritableDatabase();
97 | ContentValues cv = new ContentValues();
98 | cv.put("id", registerInfo.getId());
99 | cv.put("stu_id", registerInfo.getStuId());
100 | cv.put("name", registerInfo.getName());
101 | return db.insert(TABLE_STUDENT, null, cv);
102 | }
103 |
104 | /**
105 | * 查询学生信息
106 | *
107 | * @param id 注册id
108 | * @return 学生id
109 | */
110 | @Override
111 | @RequiresApi(api = Build.VERSION_CODES.O)
112 | public RegisterInfo getStudentInfo(int id) {
113 | SQLiteDatabase db = this.getReadableDatabase();
114 | Cursor cursor = db.query(TABLE_STUDENT, null, "id=?", new String[]{"" + id}, null, null, null);
115 | RegisterInfo registerInfo = new RegisterInfo();
116 | if (cursor.getCount() != 0) {
117 | if (cursor.moveToNext()) {
118 | registerInfo.setId(cursor.getInt(0));
119 | registerInfo.setStuId(cursor.getString(1));
120 | registerInfo.setName(cursor.getString(2));
121 | }
122 | }
123 | return registerInfo;
124 | }
125 |
126 |
127 | /**
128 | * 首页签到部分,返回具体时间
129 | * @return 返回已签到的日子
130 | */
131 | @Override
132 | @RequiresApi(api = Build.VERSION_CODES.O)
133 | public List getCalendar() {
134 | SQLiteDatabase db = this.getReadableDatabase();
135 | String[] selectionArgs = new String[1];
136 | selectionArgs[0] = String.valueOf(LocalDate.now().getYear());
137 | @SuppressLint("Recycle") Cursor cursor = db.rawQuery("SELECT distinct day,month,year FROM " + TABLE_ATTENDANCE + " WHERE year=?", selectionArgs);
138 | List historyArrayList = new ArrayList<>();
139 | while (cursor.moveToNext()) {
140 | DateHistoryTO history = new DateHistoryTO();
141 | history.setYear(cursor.getInt(2));
142 | history.setDay(cursor.getInt(0));
143 | history.setMonth(cursor.getInt(1));
144 | historyArrayList.add(history);
145 | }
146 | return historyArrayList;
147 | }
148 |
149 |
150 | /**
151 | * 签到统计部分
152 | *
153 | * @return 学号,姓名,签到时间
154 | */
155 | @Override
156 | @RequiresApi(api = Build.VERSION_CODES.O)
157 | public List getCountToday() throws ParseException {
158 | SQLiteDatabase db = this.getReadableDatabase();
159 | @SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
160 | String[] selectionArgs = new String[3];
161 | selectionArgs[0] = String.valueOf(LocalDateTime.now().getDayOfMonth());
162 | selectionArgs[1] = String.valueOf(LocalDate.now().getMonthValue());
163 | selectionArgs[2] = String.valueOf(LocalDate.now().getYear());
164 | @SuppressLint("Recycle") Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_ATTENDANCE + " WHERE day= ? and month = ? and year = ?", selectionArgs);
165 | ArrayList studentInfoTO = new ArrayList<>();
166 | while (cursor.moveToNext()) {
167 | StudentInfoTO studentInfoTO1 = new StudentInfoTO();
168 | studentInfoTO1.setDateTime(sdf.parse(cursor.getString(4)));
169 | studentInfoTO1.setStuId(cursor.getString(0));
170 | studentInfoTO1.setName(cursor.getString(1));
171 | studentInfoTO.add(studentInfoTO1);
172 | }
173 | return studentInfoTO;
174 | }
175 |
176 |
177 | /**
178 | * 考勤情况统计
179 | *
180 | * @return 当天的签到信息
181 | */
182 | @Override
183 | @RequiresApi(api = Build.VERSION_CODES.O)
184 | public History getTodayHistory() {
185 | @SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
186 | SQLiteDatabase db = this.getReadableDatabase();
187 | String[] selectionArgs = new String[3];
188 | selectionArgs[0] = String.valueOf(LocalDateTime.now().getDayOfMonth());
189 | selectionArgs[1] = String.valueOf(LocalDate.now().getMonthValue());
190 | selectionArgs[2] = String.valueOf(LocalDate.now().getYear());
191 | @SuppressLint("Recycle") Cursor cursor1 = db.rawQuery("SELECT * FROM " + TABLE_ATTENDANCE + " WHERE day= ? and month = ? and year = ? ", selectionArgs);
192 | @SuppressLint("Recycle") Cursor curso2r = db.rawQuery("SELECT * FROM " + TABLE_STUDENT, null);
193 | int count = curso2r.getCount();
194 | History history = new History();
195 | history.setDate(LocalDate.now());
196 | history.setIsSignUp(cursor1.getCount());
197 | history.setNotSigUp(count - cursor1.getCount());
198 | return history;
199 | }
200 |
201 | /**
202 | * 考勤历史(默认返回今年的),用于日历
203 | *
204 | * @return 返回一个历史数据list
205 | */
206 | @Override
207 | @RequiresApi(api = Build.VERSION_CODES.O)
208 | public List getHistory() {
209 | // 先获取当前月份
210 | SQLiteDatabase db = this.getReadableDatabase();
211 | String[] selectionArgs = new String[2];
212 | selectionArgs[0] = String.valueOf(LocalDate.now().getMonthValue());
213 | selectionArgs[1] = String.valueOf(LocalDate.now().getYear());
214 | @SuppressLint("Recycle") Cursor cursor = db.rawQuery("SELECT count(stu_id) as is_sign,month,day FROM " + TABLE_ATTENDANCE + " where month=? and year = ? group by day;", selectionArgs);
215 | @SuppressLint("Recycle") Cursor cursor1 = db.rawQuery("SELECT count(*) FROM student;", null);
216 | cursor1.moveToNext();
217 | List historyArrayList = new ArrayList<>();
218 | int total = cursor1.getInt(0);
219 | while (cursor.moveToNext()) {
220 | DateHistoryTO history = new DateHistoryTO();
221 | history.setUnSign(total-cursor.getInt(0));
222 | history.setIsSign(cursor.getInt(0));
223 | history.setDay(cursor.getInt(2));
224 | history.setMonth(cursor.getInt(1));
225 | historyArrayList.add(history);
226 | }
227 | return historyArrayList;
228 | }
229 |
230 |
231 | /**
232 | * 查询
233 | *
234 | * @param stuId 学号
235 | * @param name 用户名
236 | * @return 学生信息的list
237 | */
238 | @Override
239 | @RequiresApi(api = Build.VERSION_CODES.O)
240 | public List queryStudentInfo(String stuId, String name) throws ParseException {
241 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
242 | SQLiteDatabase db = this.getReadableDatabase();
243 | String[] selectionArgs = new String[2];
244 | selectionArgs[0] = String.valueOf(stuId);
245 | selectionArgs[1] = String.valueOf(name);
246 | String currentSqlSel;
247 | if ("".equals(name)){
248 | currentSqlSel = "SELECT * FROM " + TABLE_ATTENDANCE + " where stu_id like '%" + stuId + "%'";
249 | } else {
250 | currentSqlSel = "SELECT * FROM " + TABLE_ATTENDANCE + " where name Like '%" + name + "%'";
251 | }
252 | @SuppressLint("Recycle") Cursor cursor = db.rawQuery(currentSqlSel, null);
253 | ArrayList studentInfoTOS = new ArrayList<>();
254 | while (cursor.moveToNext()) {
255 | StudentInfoTO studentInfo = new StudentInfoTO();
256 | String datetime = cursor.getString(4);
257 | studentInfo.setName(cursor.getString(1));
258 | studentInfo.setStuId(cursor.getString(0));
259 | studentInfo.setDateTime(sdf.parse(datetime));
260 | studentInfoTOS.add(studentInfo);
261 | }
262 | return studentInfoTOS;
263 | }
264 |
265 | /**
266 | * 签到
267 | *
268 | * @param stuId 学号
269 | * @param name 用户名
270 | * @param data 当前时间
271 | * @return 是否插入成功
272 | */
273 | @Override
274 | @RequiresApi(api = Build.VERSION_CODES.O)
275 | public Boolean signUp(String stuId, String name, LocalDateTime data) {
276 | SQLiteDatabase db = this.getWritableDatabase();
277 | ContentValues cv = new ContentValues();
278 | cv.put("stu_id", stuId);
279 | cv.put("name", name);
280 | cv.put("is_Sign", Is_Sign.TURE.getCode());
281 | cv.put("day", data.getDayOfMonth());
282 | cv.put("month", data.getMonthValue());
283 | cv.put("year", data.getYear());
284 | cv.put("date", DateFormatUtils.getTodayDate());
285 | return db.insert(TABLE_ATTENDANCE, null, cv) == 1;
286 | }
287 |
288 | /**
289 | * 查询是否签到
290 | *
291 | * @param stuId 学生学号
292 | * @param data 当前时间
293 | * @return 是否签到
294 | */
295 | @Override
296 | @RequiresApi(api = Build.VERSION_CODES.O)
297 | public Boolean isSignUp(String stuId, LocalDateTime data) {
298 | SQLiteDatabase db = this.getReadableDatabase();
299 | String[] selectionArgs = new String[4];
300 | selectionArgs[0] = String.valueOf(stuId);
301 | selectionArgs[1] = String.valueOf(LocalDateTime.now().getDayOfMonth());
302 | selectionArgs[2] = String.valueOf(LocalDate.now().getMonthValue());
303 | selectionArgs[3] = String.valueOf(LocalDate.now().getYear());
304 | @SuppressLint("Recycle") Cursor cursor = db.rawQuery("SELECT * FROM " + TABLE_ATTENDANCE + " WHERE stu_id = ? and day= ? and month = ? and year = ? ", selectionArgs);
305 | return cursor.getCount() == 1;
306 | }
307 |
308 |
309 | }
310 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/service/Service.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.service;
2 |
3 | import java.text.ParseException;
4 | import java.time.LocalDate;
5 | import java.time.LocalDateTime;
6 | import java.util.List;
7 |
8 | /**
9 | * @author lenyuqin
10 | * @data 2020/12/18
11 | */
12 | public interface Service {
13 | /**
14 | * 学生注册
15 | *
16 | * @param registerInfo 学生注册信息
17 | * @return 插入条数
18 | */
19 | long studentRegister(RegisterInfo registerInfo);
20 |
21 |
22 | /**
23 | * 查询学生信息
24 | *
25 | * @param id 注册id
26 | * @return 学生id
27 | */
28 | RegisterInfo getStudentInfo(int id);
29 |
30 |
31 | /**
32 | * 首页签到部分,返回具体时间
33 | *
34 | * @return 返回已签到的日子
35 | */
36 | List getCalendar();
37 |
38 |
39 | /**
40 | * 签到统计部分
41 | *
42 | * @return 学号,姓名,签到时间
43 | */
44 | List getCountToday() throws ParseException;
45 |
46 |
47 | /**
48 | * 考勤情况统计
49 | *
50 | * @return 当天的签到信息
51 | */
52 | History getTodayHistory();
53 |
54 |
55 | /**
56 | * 考勤历史(默认返回今年的) 用于日历
57 | *
58 | * @return 返回一个历史数据list
59 | */
60 | List getHistory();
61 |
62 |
63 | /**
64 | * 查询
65 | *
66 | * @param stuId 学号
67 | * @param name 用户名
68 | * @return 学生信息的list
69 | */
70 | List queryStudentInfo(String stuId, String name) throws ParseException;
71 |
72 |
73 | /**
74 | * 签到
75 | *
76 | * @param stuId 学号
77 | * @param name 用户名
78 | * @param data 当前时间
79 | * @return 是否插入成功
80 | */
81 | Boolean signUp(String stuId, String name, LocalDateTime data);
82 |
83 |
84 | /**
85 | * 查询是否签到
86 | *
87 | * @param stuId 学生学号
88 | * @param data 当前时间
89 | * @return 是否签到
90 | */
91 | Boolean isSignUp(String stuId, LocalDateTime data);
92 |
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/service/StudentInfo.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.service;
2 |
3 | import java.time.LocalDate;
4 | import java.time.LocalDateTime;
5 | import java.util.Date;
6 |
7 | import lombok.AllArgsConstructor;
8 | import lombok.Data;
9 | import lombok.NoArgsConstructor;
10 |
11 | /**
12 | * @author lenyuqin
13 | * @data 2020/12/16
14 | */
15 | @Data
16 | @AllArgsConstructor
17 | public class StudentInfo {
18 | //学生学号
19 | private String stuId;
20 | //学生名字
21 | private String name;
22 | //是否打卡 1打卡成功,0打卡失败
23 | private int isSign;
24 | //打卡时间
25 | private LocalDate dateTime;
26 |
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/service/StudentInfoTO.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.service;
2 |
3 | import java.util.Date;
4 |
5 | import lombok.AllArgsConstructor;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | /**
10 | * @author lenyuqin
11 | * @data 2020/12/18
12 | */
13 | @Data
14 | @AllArgsConstructor
15 | @NoArgsConstructor
16 | public class StudentInfoTO {
17 | //学生学号
18 | private String stuId;
19 | //学生名字
20 | private String name;
21 | //打卡时间
22 | private Date dateTime;
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/ConfigUtil.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 |
6 | import com.arcsoft.face.enums.DetectFaceOrientPriority;
7 |
8 | public class ConfigUtil {
9 | private static final String APP_NAME = "faceapp";
10 | private static final String TRACKED_FACE_COUNT = "trackedFaceCount";
11 | private static final String FT_ORIENT = "ftOrientPriority";
12 | private static final String MAC_PRIORITY = "macPriority";
13 |
14 | public static boolean setTrackedFaceCount(Context context, int trackedFaceCount) {
15 | if (context == null) {
16 | return false;
17 | }
18 | SharedPreferences sharedPreferences = context.getSharedPreferences(APP_NAME, Context.MODE_PRIVATE);
19 | return sharedPreferences.edit()
20 | .putInt(TRACKED_FACE_COUNT, trackedFaceCount)
21 | .commit();
22 | }
23 |
24 | public static int getTrackedFaceCount(Context context) {
25 | if (context == null) {
26 | return 0;
27 | }
28 | SharedPreferences sharedPreferences = context.getSharedPreferences(APP_NAME, Context.MODE_PRIVATE);
29 | return sharedPreferences.getInt(TRACKED_FACE_COUNT, 0);
30 | }
31 |
32 | public static boolean setFtOrient(Context context, DetectFaceOrientPriority ftOrient) {
33 | if (context == null) {
34 | return false;
35 | }
36 | SharedPreferences sharedPreferences = context.getSharedPreferences(APP_NAME, Context.MODE_PRIVATE);
37 | return sharedPreferences.edit().putString(FT_ORIENT, ftOrient.name()).commit();
38 | }
39 |
40 | public static DetectFaceOrientPriority getFtOrient(Context context) {
41 | if (context == null) {
42 | return DetectFaceOrientPriority.ASF_OP_270_ONLY;
43 | }
44 | SharedPreferences sharedPreferences = context.getSharedPreferences(APP_NAME, Context.MODE_PRIVATE);
45 | return DetectFaceOrientPriority.valueOf(sharedPreferences.getString(FT_ORIENT, DetectFaceOrientPriority.ASF_OP_270_ONLY.name()));
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/DrawHelper.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.graphics.Path;
6 | import android.graphics.Rect;
7 | import android.hardware.Camera;
8 |
9 | import com.arcsoft.face.AgeInfo;
10 | import com.arcsoft.face.GenderInfo;
11 | import com.arcsoft.face.LivenessInfo;
12 | import com.xiaoyou.face.model.DrawInfo;
13 | import com.xiaoyou.face.widget.FaceRectView;
14 |
15 | import java.util.List;
16 |
17 | /**
18 | * 绘制人脸框帮助类,用于在{@link com.xiaoyou.face.widget.FaceRectView}上绘制矩形
19 | */
20 | public class DrawHelper {
21 | private int previewWidth, previewHeight, canvasWidth, canvasHeight, cameraDisplayOrientation, cameraId;
22 | private boolean isMirror;
23 | private boolean mirrorHorizontal = false, mirrorVertical = false;
24 |
25 | /**
26 | * 创建一个绘制辅助类对象,并且设置绘制相关的参数
27 | *
28 | * @param previewWidth 预览宽度
29 | * @param previewHeight 预览高度
30 | * @param canvasWidth 绘制控件的宽度
31 | * @param canvasHeight 绘制控件的高度
32 | * @param cameraDisplayOrientation 旋转角度
33 | * @param cameraId 相机ID
34 | * @param isMirror 是否水平镜像显示(若相机是镜像显示的,设为true,用于纠正)
35 | * @param mirrorHorizontal 为兼容部分设备使用,水平再次镜像
36 | * @param mirrorVertical 为兼容部分设备使用,垂直再次镜像
37 | */
38 | public DrawHelper(int previewWidth, int previewHeight, int canvasWidth,
39 | int canvasHeight, int cameraDisplayOrientation, int cameraId,
40 | boolean isMirror, boolean mirrorHorizontal, boolean mirrorVertical) {
41 | this.previewWidth = previewWidth;
42 | this.previewHeight = previewHeight;
43 | this.canvasWidth = canvasWidth;
44 | this.canvasHeight = canvasHeight;
45 | this.cameraDisplayOrientation = cameraDisplayOrientation;
46 | this.cameraId = cameraId;
47 | this.isMirror = isMirror;
48 | this.mirrorHorizontal = mirrorHorizontal;
49 | this.mirrorVertical = mirrorVertical;
50 | }
51 |
52 | public void draw(FaceRectView faceRectView, List drawInfoList) {
53 | if (faceRectView == null) {
54 | return;
55 | }
56 | faceRectView.clearFaceInfo();
57 | if (drawInfoList == null || drawInfoList.size() == 0) {
58 | return;
59 | }
60 | faceRectView.addFaceInfo(drawInfoList);
61 | }
62 |
63 | /**
64 | * 调整人脸框用来绘制
65 | *
66 | * @param ftRect FT人脸框
67 | * @return 调整后的需要被绘制到View上的rect
68 | */
69 | public Rect adjustRect(Rect ftRect) {
70 | int previewWidth = this.previewWidth;
71 | int previewHeight = this.previewHeight;
72 | int canvasWidth = this.canvasWidth;
73 | int canvasHeight = this.canvasHeight;
74 | int cameraDisplayOrientation = this.cameraDisplayOrientation;
75 | int cameraId = this.cameraId;
76 | boolean isMirror = this.isMirror;
77 | boolean mirrorHorizontal = this.mirrorHorizontal;
78 | boolean mirrorVertical = this.mirrorVertical;
79 |
80 | if (ftRect == null) {
81 | return null;
82 | }
83 |
84 | Rect rect = new Rect(ftRect);
85 | float horizontalRatio;
86 | float verticalRatio;
87 | if (cameraDisplayOrientation % 180 == 0) {
88 | horizontalRatio = (float) canvasWidth / (float) previewWidth;
89 | verticalRatio = (float) canvasHeight / (float) previewHeight;
90 | } else {
91 | horizontalRatio = (float) canvasHeight / (float) previewWidth;
92 | verticalRatio = (float) canvasWidth / (float) previewHeight;
93 | }
94 | rect.left *= horizontalRatio;
95 | rect.right *= horizontalRatio;
96 | rect.top *= verticalRatio;
97 | rect.bottom *= verticalRatio;
98 |
99 | Rect newRect = new Rect();
100 | switch (cameraDisplayOrientation) {
101 | case 0:
102 | if (cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
103 | newRect.left = canvasWidth - rect.right;
104 | newRect.right = canvasWidth - rect.left;
105 | } else {
106 | newRect.left = rect.left;
107 | newRect.right = rect.right;
108 | }
109 | newRect.top = rect.top;
110 | newRect.bottom = rect.bottom;
111 | break;
112 | case 90:
113 | newRect.right = canvasWidth - rect.top;
114 | newRect.left = canvasWidth - rect.bottom;
115 | if (cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
116 | newRect.top = canvasHeight - rect.right;
117 | newRect.bottom = canvasHeight - rect.left;
118 | } else {
119 | newRect.top = rect.left;
120 | newRect.bottom = rect.right;
121 | }
122 | break;
123 | case 180:
124 | newRect.top = canvasHeight - rect.bottom;
125 | newRect.bottom = canvasHeight - rect.top;
126 | if (cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
127 | newRect.left = rect.left;
128 | newRect.right = rect.right;
129 | } else {
130 | newRect.left = canvasWidth - rect.right;
131 | newRect.right = canvasWidth - rect.left;
132 | }
133 | break;
134 | case 270:
135 | newRect.left = rect.top;
136 | newRect.right = rect.bottom;
137 | if (cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT) {
138 | newRect.top = rect.left;
139 | newRect.bottom = rect.right;
140 | } else {
141 | newRect.top = canvasHeight - rect.right;
142 | newRect.bottom = canvasHeight - rect.left;
143 | }
144 | break;
145 | default:
146 | break;
147 | }
148 |
149 | /**
150 | * isMirror mirrorHorizontal finalIsMirrorHorizontal
151 | * true true false
152 | * false false false
153 | * true false true
154 | * false true true
155 | *
156 | * XOR
157 | */
158 | if (isMirror ^ mirrorHorizontal) {
159 | int left = newRect.left;
160 | int right = newRect.right;
161 | newRect.left = canvasWidth - right;
162 | newRect.right = canvasWidth - left;
163 | }
164 | if (mirrorVertical) {
165 | int top = newRect.top;
166 | int bottom = newRect.bottom;
167 | newRect.top = canvasHeight - bottom;
168 | newRect.bottom = canvasHeight - top;
169 | }
170 | return newRect;
171 | }
172 |
173 | /**
174 | * 绘制数据信息到view上,若 {@link DrawInfo#getName()} 不为null则绘制 {@link DrawInfo#getName()}
175 | *
176 | * @param canvas 需要被绘制的view的canvas
177 | * @param drawInfo 绘制信息
178 | * @param faceRectThickness 人脸框厚度
179 | * @param paint 画笔
180 | */
181 | public static void drawFaceRect(Canvas canvas, DrawInfo drawInfo, int faceRectThickness, Paint paint) {
182 | if (canvas == null || drawInfo == null) {
183 | return;
184 | }
185 | paint.setStyle(Paint.Style.STROKE);
186 | paint.setStrokeWidth(faceRectThickness);
187 | paint.setColor(drawInfo.getColor());
188 | paint.setAntiAlias(true);
189 |
190 | Path mPath = new Path();
191 | // 左上
192 | Rect rect = drawInfo.getRect();
193 | mPath.moveTo(rect.left, rect.top + rect.height() / 4);
194 | mPath.lineTo(rect.left, rect.top);
195 | mPath.lineTo(rect.left + rect.width() / 4, rect.top);
196 | // 右上
197 | mPath.moveTo(rect.right - rect.width() / 4, rect.top);
198 | mPath.lineTo(rect.right, rect.top);
199 | mPath.lineTo(rect.right, rect.top + rect.height() / 4);
200 | // 右下
201 | mPath.moveTo(rect.right, rect.bottom - rect.height() / 4);
202 | mPath.lineTo(rect.right, rect.bottom);
203 | mPath.lineTo(rect.right - rect.width() / 4, rect.bottom);
204 | // 左下
205 | mPath.moveTo(rect.left + rect.width() / 4, rect.bottom);
206 | mPath.lineTo(rect.left, rect.bottom);
207 | mPath.lineTo(rect.left, rect.bottom - rect.height() / 4);
208 | canvas.drawPath(mPath, paint);
209 |
210 | // 绘制文字,用最细的即可,避免在某些低像素设备上文字模糊
211 | paint.setStrokeWidth(1);
212 |
213 | if (drawInfo.getName() == null) {
214 | paint.setStyle(Paint.Style.FILL_AND_STROKE);
215 | paint.setTextSize(rect.width() / 8);
216 |
217 | String str = (drawInfo.getSex() == GenderInfo.MALE ? "MALE" : (drawInfo.getSex() == GenderInfo.FEMALE ? "FEMALE" : "UNKNOWN"))
218 | + ","
219 | + (drawInfo.getAge() == AgeInfo.UNKNOWN_AGE ? "UNKNOWN" : drawInfo.getAge())
220 | + ","
221 | + (drawInfo.getLiveness() == LivenessInfo.ALIVE ? "ALIVE" : (drawInfo.getLiveness() == LivenessInfo.NOT_ALIVE ? "NOT_ALIVE" : "UNKNOWN"));
222 | canvas.drawText(str, rect.left, rect.top - 10, paint);
223 | } else {
224 | paint.setStyle(Paint.Style.FILL_AND_STROKE);
225 | paint.setTextSize(rect.width() / 8);
226 | canvas.drawText(drawInfo.getName(), rect.left, rect.top - 10, paint);
227 | }
228 | }
229 |
230 | public void setPreviewWidth(int previewWidth) {
231 | this.previewWidth = previewWidth;
232 | }
233 |
234 | public void setPreviewHeight(int previewHeight) {
235 | this.previewHeight = previewHeight;
236 | }
237 |
238 | public void setCanvasWidth(int canvasWidth) {
239 | this.canvasWidth = canvasWidth;
240 | }
241 |
242 | public void setCanvasHeight(int canvasHeight) {
243 | this.canvasHeight = canvasHeight;
244 | }
245 |
246 | public void setCameraDisplayOrientation(int cameraDisplayOrientation) {
247 | this.cameraDisplayOrientation = cameraDisplayOrientation;
248 | }
249 |
250 | public void setCameraId(int cameraId) {
251 | this.cameraId = cameraId;
252 | }
253 |
254 | public void setMirror(boolean mirror) {
255 | isMirror = mirror;
256 | }
257 |
258 | public int getPreviewWidth() {
259 | return previewWidth;
260 | }
261 |
262 | public int getPreviewHeight() {
263 | return previewHeight;
264 | }
265 |
266 | public int getCanvasWidth() {
267 | return canvasWidth;
268 | }
269 |
270 | public int getCanvasHeight() {
271 | return canvasHeight;
272 | }
273 |
274 | public int getCameraDisplayOrientation() {
275 | return cameraDisplayOrientation;
276 | }
277 |
278 | public int getCameraId() {
279 | return cameraId;
280 | }
281 |
282 | public boolean isMirror() {
283 | return isMirror;
284 | }
285 |
286 | public boolean isMirrorHorizontal() {
287 | return mirrorHorizontal;
288 | }
289 |
290 | public void setMirrorHorizontal(boolean mirrorHorizontal) {
291 | this.mirrorHorizontal = mirrorHorizontal;
292 | }
293 |
294 | public boolean isMirrorVertical() {
295 | return mirrorVertical;
296 | }
297 |
298 | public void setMirrorVertical(boolean mirrorVertical) {
299 | this.mirrorVertical = mirrorVertical;
300 | }
301 | }
302 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/PieChartManager.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils;
2 |
3 | import android.graphics.Color;
4 | import android.graphics.Typeface;
5 |
6 | import com.github.mikephil.charting.charts.PieChart;
7 | import com.github.mikephil.charting.components.Legend;
8 | import com.github.mikephil.charting.data.PieData;
9 | import com.github.mikephil.charting.data.PieDataSet;
10 | import com.github.mikephil.charting.data.PieEntry;
11 | import com.github.mikephil.charting.formatter.PercentFormatter;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * 圆环管理类
17 | * @author 小游
18 | * @date 2020/12/16
19 | */
20 | public class PieChartManager {
21 | public PieChart pieChart;
22 |
23 | public PieChartManager(PieChart pieChart) {
24 | this.pieChart = pieChart;
25 | initPieChart();
26 | }
27 |
28 | //初始化
29 | private void initPieChart() {
30 | // 是否显示中间的洞
31 | pieChart.setDrawHoleEnabled(false);
32 | //设置中间洞的大小
33 | pieChart.setHoleRadius(40f);
34 |
35 | // 半透明圈
36 | pieChart.setTransparentCircleRadius(30f);
37 | //设置半透明圆圈的颜色
38 | pieChart.setTransparentCircleColor(Color.WHITE);
39 | //设置半透明圆圈的透明度
40 | pieChart.setTransparentCircleAlpha(125);
41 |
42 |
43 | //饼状图中间可以添加文字
44 | pieChart.setDrawCenterText(false);
45 | //设置中间文字
46 | pieChart.setCenterText("民族");
47 | //中间问题的颜色
48 | pieChart.setCenterTextColor(Color.parseColor("#a1a1a1"));
49 | //中间文字的大小px
50 | pieChart.setCenterTextSizePixels(36);
51 | pieChart.setCenterTextRadiusPercent(1f);
52 | //中间文字的样式
53 | pieChart.setCenterTextTypeface(Typeface.DEFAULT);
54 | //中间文字的偏移量
55 | pieChart.setCenterTextOffset(0, 0);
56 |
57 | // 初始旋转角度
58 | pieChart.setRotationAngle(0);
59 | // 可以手动旋转
60 | pieChart.setRotationEnabled(true);
61 | //显示成百分比
62 | pieChart.setUsePercentValues(true);
63 | //取消右下角描述
64 | pieChart.getDescription().setEnabled(false);
65 |
66 | //是否显示每个部分的文字描述
67 | pieChart.setDrawEntryLabels(false);
68 | //描述文字的颜色
69 | pieChart.setEntryLabelColor(Color.RED);
70 | //描述文字的大小
71 | pieChart.setEntryLabelTextSize(14);
72 | //描述文字的样式
73 | pieChart.setEntryLabelTypeface(Typeface.DEFAULT_BOLD);
74 |
75 | //图相对于上下左右的偏移
76 | pieChart.setExtraOffsets(20, 8, 75, 8);
77 | //图标的背景色
78 | pieChart.setBackgroundColor(Color.TRANSPARENT);
79 | // 设置pieChart图表转动阻力摩擦系数[0,1]
80 | pieChart.setDragDecelerationFrictionCoef(0.75f);
81 |
82 | //获取图例
83 | Legend legend = pieChart.getLegend();
84 | //设置图例水平显示
85 | legend.setOrientation(Legend.LegendOrientation.VERTICAL);
86 | //顶部
87 | legend.setVerticalAlignment(Legend.LegendVerticalAlignment.TOP);
88 | //右对其
89 | legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.RIGHT);
90 |
91 | //x轴的间距
92 | legend.setXEntrySpace(7f);
93 | //y轴的间距
94 | legend.setYEntrySpace(10f);
95 | //图例的y偏移量
96 | legend.setYOffset(10f);
97 | //图例x的偏移量
98 | legend.setXOffset(10f);
99 | //图例文字的颜色
100 | legend.setTextColor(Color.parseColor("#a1a1a1"));
101 | //图例文字的大小
102 | legend.setTextSize(13);
103 |
104 | }
105 |
106 |
107 | /**
108 | * 显示实心圆
109 | * @param yvals
110 | * @param colors
111 | */
112 | public void showSolidPieChart(List yvals, List colors) {
113 | //数据集合
114 | PieDataSet dataset = new PieDataSet(yvals, "");
115 | //填充每个区域的颜色
116 | dataset.setColors(colors);
117 | //是否在图上显示数值
118 | dataset.setDrawValues(true);
119 | // 文字的大小
120 | dataset.setValueTextSize(14);
121 | // 文字的颜色
122 | dataset.setValueTextColor(Color.RED);
123 | // 文字的样式
124 | dataset.setValueTypeface(Typeface.DEFAULT_BOLD);
125 |
126 | // 当值位置为外边线时,表示线的前半段长度。
127 | dataset.setValueLinePart1Length(0.4f);
128 | // 当值位置为外边线时,表示线的后半段长度。
129 | dataset.setValueLinePart2Length(0.4f);
130 | // 当ValuePosits为OutsiDice时,指示偏移为切片大小的百分比
131 | dataset.setValueLinePart1OffsetPercentage(80f);
132 | // 当值位置为外边线时,表示线的颜色。
133 | dataset.setValueLineColor(Color.parseColor("#a1a1a1"));
134 | // 设置Y值的位置是在圆内还是圆外
135 | dataset.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
136 | // 设置Y轴描述线和填充区域的颜色一致
137 | dataset.setUsingSliceColorAsValueLineColor(false);
138 | // 设置每条之前的间隙
139 | dataset.setSliceSpace(0);
140 |
141 | //设置饼状Item被选中时变化的距离
142 | dataset.setSelectionShift(5f);
143 | //填充数据
144 | PieData pieData = new PieData(dataset);
145 | // 格式化显示的数据为%百分比
146 | pieData.setValueFormatter(new PercentFormatter());
147 | // 显示试图
148 | pieChart.setData(pieData);
149 | }
150 |
151 |
152 | /**
153 | * 显示圆环
154 | * @param yvals
155 | * @param colors
156 | */
157 | public void showRingPieChart(List yvals, List colors){
158 | //显示为圆环
159 | pieChart.setDrawHoleEnabled(true);
160 | //设置中间洞的大小
161 | pieChart.setHoleRadius(10f);
162 |
163 | //数据集合
164 | PieDataSet dataset = new PieDataSet(yvals, "");
165 | //填充每个区域的颜色
166 | dataset.setColors(colors);
167 | //是否在图上显示数值
168 | dataset.setDrawValues(true);
169 | // 文字的大小
170 | dataset.setValueTextSize(14);
171 | // 文字的颜色
172 | dataset.setValueTextColor(Color.RED);
173 | // 文字的样式
174 | dataset.setValueTypeface(Typeface.DEFAULT_BOLD);
175 |
176 | // 当值位置为外边线时,表示线的前半段长度。
177 | dataset.setValueLinePart1Length(0.4f);
178 | // 当值位置为外边线时,表示线的后半段长度。
179 | dataset.setValueLinePart2Length(0.4f);
180 | // 当ValuePosits为OutsiDice时,指示偏移为切片大小的百分比
181 | dataset.setValueLinePart1OffsetPercentage(80f);
182 | // 当值位置为外边线时,表示线的颜色。
183 | dataset.setValueLineColor(Color.parseColor("#a1a1a1"));
184 | // 设置Y值的位置是在圆内还是圆外
185 | dataset.setYValuePosition(PieDataSet.ValuePosition.OUTSIDE_SLICE);
186 | // 设置Y轴描述线和填充区域的颜色一致
187 | dataset.setUsingSliceColorAsValueLineColor(false);
188 | // 设置每条之前的间隙
189 | dataset.setSliceSpace(0);
190 |
191 | //设置饼状Item被选中时变化的距离
192 | dataset.setSelectionShift(5f);
193 | //填充数据
194 | PieData pieData = new PieData(dataset);
195 | // 格式化显示的数据为%百分比
196 | pieData.setValueFormatter(new PercentFormatter());
197 | // 显示试图
198 | pieChart.setData(pieData);
199 |
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/ToastUtils.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils;
2 |
3 | import android.annotation.SuppressLint;
4 |
5 | import androidx.annotation.MainThread;
6 | import androidx.annotation.NonNull;
7 | import androidx.annotation.StringRes;
8 |
9 | import com.xuexiang.xui.XUI;
10 | import com.xuexiang.xui.widget.toast.XToast;
11 |
12 | /**
13 | * 自定义弹框函数
14 | * @author 小游
15 | * @date 2020/12/15
16 | */
17 | @SuppressLint("CheckResult")
18 | public final class ToastUtils {
19 |
20 | private ToastUtils() {
21 | throw new UnsupportedOperationException("u can't instantiate me...");
22 | }
23 |
24 | static {
25 | XToast.Config.get()
26 | .setAlpha(200)
27 | .setToastTypeface(XUI.getDefaultTypeface())
28 | .allowQueue(false);
29 | }
30 |
31 |
32 | @MainThread
33 | public static void toast(@NonNull CharSequence message) {
34 | XToast.normal(XUI.getContext(), message).show();
35 | }
36 |
37 | @MainThread
38 | public static void toast(@StringRes int message) {
39 | XToast.normal(XUI.getContext(), message).show();
40 | }
41 |
42 | @MainThread
43 | public static void toast(@NonNull CharSequence message, int duration) {
44 | XToast.normal(XUI.getContext(), message, duration).show();
45 | }
46 |
47 | @MainThread
48 | public static void toast(@StringRes int message, int duration) {
49 | XToast.normal(XUI.getContext(), message, duration).show();
50 | }
51 |
52 | //=============//
53 |
54 | @MainThread
55 | public static void error(@NonNull CharSequence message) {
56 | XToast.error(XUI.getContext(), message).show();
57 | }
58 |
59 | @MainThread
60 | public static void error(@NonNull Exception error) {
61 | XToast.error(XUI.getContext(), error.getMessage()).show();
62 | }
63 |
64 | @MainThread
65 | public static void error(@StringRes int message) {
66 | XToast.error(XUI.getContext(), message).show();
67 | }
68 |
69 | @MainThread
70 | public static void error(@NonNull CharSequence message, int duration) {
71 | XToast.error(XUI.getContext(), message, duration).show();
72 | }
73 |
74 | @MainThread
75 | public static void error(@StringRes int message, int duration) {
76 | XToast.error(XUI.getContext(), message, duration).show();
77 | }
78 |
79 | //=============//
80 |
81 | @MainThread
82 | public static void success(@NonNull CharSequence message) {
83 | XToast.success(XUI.getContext(), message).show();
84 | }
85 |
86 | @MainThread
87 | public static void success(@StringRes int message) {
88 | XToast.success(XUI.getContext(), message).show();
89 | }
90 |
91 | @MainThread
92 | public static void success(@NonNull CharSequence message, int duration) {
93 | XToast.success(XUI.getContext(), message, duration).show();
94 | }
95 |
96 | @MainThread
97 | public static void success(@StringRes int message, int duration) {
98 | XToast.success(XUI.getContext(), message, duration).show();
99 | }
100 |
101 | //=============//
102 |
103 | @MainThread
104 | public static void info(@NonNull CharSequence message) {
105 | XToast.info(XUI.getContext(), message).show();
106 | }
107 |
108 | @MainThread
109 | public static void info(@StringRes int message) {
110 | XToast.info(XUI.getContext(), message).show();
111 | }
112 |
113 | @MainThread
114 | public static void info(@NonNull CharSequence message, int duration) {
115 | XToast.info(XUI.getContext(), message, duration).show();
116 | }
117 |
118 | @MainThread
119 | public static void info(@StringRes int message, int duration) {
120 | XToast.info(XUI.getContext(), message, duration).show();
121 | }
122 |
123 | //=============//
124 |
125 | @MainThread
126 | public static void warning(@NonNull CharSequence message) {
127 | XToast.warning(XUI.getContext(), message).show();
128 | }
129 |
130 | @MainThread
131 | public static void warning(@StringRes int message) {
132 | XToast.warning(XUI.getContext(), message).show();
133 | }
134 |
135 | @MainThread
136 | public static void warning(@NonNull CharSequence message, int duration) {
137 | XToast.warning(XUI.getContext(), message, duration).show();
138 | }
139 |
140 | @MainThread
141 | public static void warning(@StringRes int message, int duration) {
142 | XToast.warning(XUI.getContext(), message, duration).show();
143 | }
144 |
145 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/Tools.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils;
2 |
3 | import android.content.Context;
4 | import android.content.res.Resources;
5 | import android.graphics.Color;
6 | import android.util.DisplayMetrics;
7 |
8 | import java.util.Random;
9 |
10 | /**
11 | * 一些常用的工具类
12 | * @author 小游
13 | * @date 2020/12/18
14 | */
15 | public class Tools {
16 |
17 | /**
18 | * 随机获取一个颜色
19 | * @return 颜色值
20 | */
21 | public static int getRandomColor(){
22 | // 存储颜色数组
23 | String[] colors = new String[]{
24 | "#1abc9c",
25 | "#2ecc71",
26 | "#3498db",
27 | "#9b59b6",
28 | "#34495e",
29 | "#f1c40f",
30 | "#e67e22",
31 | "#e74c3c",
32 | "#ecf0f1",
33 | "#95a5a6",
34 | "#95a5a6",
35 | };
36 | // 随机获取一个颜色
37 | Random random = new Random();
38 | return Color.parseColor(colors[random.nextInt(colors.length)]);
39 | }
40 |
41 |
42 | /**
43 | * 获取系统的屏幕宽度
44 | * @param context context对象
45 | * @return 返回当前宽度(单位px)
46 | */
47 | public static int getWidth(Context context){
48 | Resources resources = context.getResources();
49 | DisplayMetrics dm = resources.getDisplayMetrics();
50 | return dm.widthPixels;
51 | }
52 |
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/TrackUtil.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils;
2 |
3 | import com.arcsoft.face.FaceInfo;
4 |
5 | import java.util.List;
6 |
7 | public class TrackUtil {
8 |
9 | public static boolean isSameFace(FaceInfo faceInfo1, FaceInfo faceInfo2) {
10 | return faceInfo1.getFaceId() == faceInfo2.getFaceId();
11 | }
12 |
13 | public static void keepMaxFace(List ftFaceList) {
14 | if (ftFaceList == null || ftFaceList.size() <= 1) {
15 | return;
16 | }
17 | FaceInfo maxFaceInfo = ftFaceList.get(0);
18 | for (FaceInfo faceInfo : ftFaceList) {
19 | if (faceInfo.getRect().width() > maxFaceInfo.getRect().width()) {
20 | maxFaceInfo = faceInfo;
21 | }
22 | }
23 | ftFaceList.clear();
24 | ftFaceList.add(maxFaceInfo);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/TypeChange.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils;
2 |
3 | import android.graphics.Bitmap;
4 |
5 | import java.io.ByteArrayInputStream;
6 | import java.io.ByteArrayOutputStream;
7 | import java.io.InputStream;
8 |
9 | /**
10 | * 类型转换函数
11 | *
12 | * @author 小游
13 | * @date 2020/12/15
14 | */
15 | public class TypeChange {
16 | /**
17 | * bitmap对象转string
18 | * @param bm bitmap对象
19 | * @return 返回InputStream 对象
20 | */
21 | public static InputStream bitmap2InputStream(Bitmap bm) {
22 | ByteArrayOutputStream bao = new ByteArrayOutputStream();
23 | bm.compress(Bitmap.CompressFormat.JPEG, 100, bao);
24 | return new ByteArrayInputStream(bao.toByteArray());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/camera/CameraHelper.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils.camera;
2 |
3 | import android.graphics.ImageFormat;
4 | import android.graphics.Point;
5 | import android.graphics.SurfaceTexture;
6 | import android.hardware.Camera;
7 | import android.util.Log;
8 | import android.view.Surface;
9 | import android.view.SurfaceHolder;
10 | import android.view.SurfaceView;
11 | import android.view.TextureView;
12 | import android.view.View;
13 |
14 | import java.io.IOException;
15 | import java.util.Arrays;
16 | import java.util.Comparator;
17 | import java.util.List;
18 |
19 | /**
20 | * 相机辅助类,和{@link CameraListener}共同使用,获取nv21数据等操作
21 | */
22 | public class CameraHelper implements Camera.PreviewCallback {
23 | private static final String TAG = "CameraHelper";
24 | private Camera mCamera;
25 | private int mCameraId;
26 | private Point previewViewSize;
27 | private View previewDisplayView;
28 | private Camera.Size previewSize;
29 | private Point specificPreviewSize;
30 | private int displayOrientation = 0;
31 | private int rotation;
32 | private int additionalRotation;
33 | private boolean isMirror = false;
34 |
35 | private Integer specificCameraId = null;
36 | private CameraListener cameraListener;
37 |
38 | private CameraHelper(Builder builder) {
39 | previewDisplayView = builder.previewDisplayView;
40 | specificCameraId = builder.specificCameraId;
41 | cameraListener = builder.cameraListener;
42 | rotation = builder.rotation;
43 | additionalRotation = builder.additionalRotation;
44 | previewViewSize = builder.previewViewSize;
45 | specificPreviewSize = builder.previewSize;
46 | if (builder.previewDisplayView instanceof TextureView) {
47 | isMirror = builder.isMirror;
48 | } else if (isMirror) {
49 | throw new RuntimeException("mirror is effective only when the preview is on a textureView");
50 | }
51 | }
52 |
53 | public void init() {
54 | if (previewDisplayView instanceof TextureView) {
55 | ((TextureView) this.previewDisplayView).setSurfaceTextureListener(textureListener);
56 | } else if (previewDisplayView instanceof SurfaceView) {
57 | ((SurfaceView) previewDisplayView).getHolder().addCallback(surfaceCallback);
58 | }
59 |
60 | if (isMirror) {
61 | previewDisplayView.setScaleX(-1);
62 | }
63 | }
64 |
65 | public void start() {
66 | synchronized (this) {
67 | if (mCamera != null) {
68 | return;
69 | }
70 | //相机数量为2则打开1,1则打开0,相机ID 1为前置,0为后置
71 | mCameraId = Camera.getNumberOfCameras() - 1;
72 | //若指定了相机ID且该相机存在,则打开指定的相机
73 | if (specificCameraId != null && specificCameraId <= mCameraId) {
74 | mCameraId = specificCameraId;
75 | }
76 |
77 | //没有相机
78 | if (mCameraId == -1) {
79 | if (cameraListener != null) {
80 | cameraListener.onCameraError(new Exception("camera not found"));
81 | }
82 | return;
83 | }
84 | if (mCamera == null) {
85 | mCamera = Camera.open(mCameraId);
86 | }
87 |
88 | displayOrientation = getCameraOri(rotation);
89 | mCamera.setDisplayOrientation(displayOrientation);
90 | try {
91 | Camera.Parameters parameters = mCamera.getParameters();
92 | parameters.setPreviewFormat(ImageFormat.NV21);
93 |
94 | //预览大小设置
95 | previewSize = parameters.getPreviewSize();
96 | List supportedPreviewSizes = parameters.getSupportedPreviewSizes();
97 | if (supportedPreviewSizes != null && supportedPreviewSizes.size() > 0) {
98 | previewSize = getBestSupportedSize(supportedPreviewSizes, previewViewSize);
99 | }
100 | parameters.setPreviewSize(previewSize.width, previewSize.height);
101 |
102 | //对焦模式设置
103 | List supportedFocusModes = parameters.getSupportedFocusModes();
104 | if (supportedFocusModes != null && supportedFocusModes.size() > 0) {
105 | if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
106 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
107 | } else if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
108 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
109 | } else if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
110 | parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
111 | }
112 | }
113 | mCamera.setParameters(parameters);
114 | if (previewDisplayView instanceof TextureView) {
115 | mCamera.setPreviewTexture(((TextureView) previewDisplayView).getSurfaceTexture());
116 | } else {
117 | mCamera.setPreviewDisplay(((SurfaceView) previewDisplayView).getHolder());
118 | }
119 | mCamera.setPreviewCallback(this);
120 | mCamera.startPreview();
121 | if (cameraListener != null) {
122 | cameraListener.onCameraOpened(mCamera, mCameraId, displayOrientation, isMirror);
123 | }
124 | } catch (Exception e) {
125 | if (cameraListener != null) {
126 | cameraListener.onCameraError(e);
127 | }
128 | }
129 | }
130 | }
131 |
132 | private int getCameraOri(int rotation) {
133 | int degrees = rotation * 90;
134 | switch (rotation) {
135 | case Surface.ROTATION_0:
136 | degrees = 0;
137 | break;
138 | case Surface.ROTATION_90:
139 | degrees = 90;
140 | break;
141 | case Surface.ROTATION_180:
142 | degrees = 180;
143 | break;
144 | case Surface.ROTATION_270:
145 | degrees = 270;
146 | break;
147 | default:
148 | break;
149 | }
150 | additionalRotation /= 90;
151 | additionalRotation *= 90;
152 | degrees += additionalRotation;
153 | int result;
154 | Camera.CameraInfo info = new Camera.CameraInfo();
155 | Camera.getCameraInfo(mCameraId, info);
156 | if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
157 | result = (info.orientation + degrees) % 360;
158 | result = (360 - result) % 360;
159 | } else {
160 | result = (info.orientation - degrees + 360) % 360;
161 | }
162 | return result;
163 | }
164 |
165 | public void stop() {
166 | synchronized (this) {
167 | if (mCamera == null) {
168 | return;
169 | }
170 | mCamera.setPreviewCallback(null);
171 | mCamera.stopPreview();
172 | mCamera.release();
173 | mCamera = null;
174 | if (cameraListener != null) {
175 | cameraListener.onCameraClosed();
176 | }
177 | }
178 | }
179 |
180 | public boolean isStopped() {
181 | synchronized (this) {
182 | return mCamera == null;
183 | }
184 | }
185 |
186 | public void release() {
187 | synchronized (this) {
188 | stop();
189 | previewDisplayView = null;
190 | specificCameraId = null;
191 | cameraListener = null;
192 | previewViewSize = null;
193 | specificPreviewSize = null;
194 | previewSize = null;
195 | }
196 | }
197 |
198 | private Camera.Size getBestSupportedSize(List sizes, Point previewViewSize) {
199 | if (sizes == null || sizes.size() == 0) {
200 | return mCamera.getParameters().getPreviewSize();
201 | }
202 | Camera.Size[] tempSizes = sizes.toArray(new Camera.Size[0]);
203 | Arrays.sort(tempSizes, new Comparator() {
204 | @Override
205 | public int compare(Camera.Size o1, Camera.Size o2) {
206 | if (o1.width > o2.width) {
207 | return -1;
208 | } else if (o1.width == o2.width) {
209 | return o1.height > o2.height ? -1 : 1;
210 | } else {
211 | return 1;
212 | }
213 | }
214 | });
215 | sizes = Arrays.asList(tempSizes);
216 |
217 | Camera.Size bestSize = sizes.get(0);
218 | float previewViewRatio;
219 | if (previewViewSize != null) {
220 | previewViewRatio = (float) previewViewSize.x / (float) previewViewSize.y;
221 | } else {
222 | previewViewRatio = (float) bestSize.width / (float) bestSize.height;
223 | }
224 |
225 | if (previewViewRatio > 1) {
226 | previewViewRatio = 1 / previewViewRatio;
227 | }
228 | boolean isNormalRotate = (additionalRotation % 180 == 0);
229 |
230 | for (Camera.Size s : sizes) {
231 | if (specificPreviewSize != null && specificPreviewSize.x == s.width && specificPreviewSize.y == s.height) {
232 | return s;
233 | }
234 | if (isNormalRotate) {
235 | if (Math.abs((s.height / (float) s.width) - previewViewRatio) < Math.abs(bestSize.height / (float) bestSize.width - previewViewRatio)) {
236 | bestSize = s;
237 | }
238 | } else {
239 | if (Math.abs((s.width / (float) s.height) - previewViewRatio) < Math.abs(bestSize.width / (float) bestSize.height - previewViewRatio)) {
240 | bestSize = s;
241 | }
242 | }
243 | }
244 | return bestSize;
245 | }
246 |
247 | public List getSupportedPreviewSizes() {
248 | if (mCamera == null) {
249 | return null;
250 | }
251 | return mCamera.getParameters().getSupportedPreviewSizes();
252 | }
253 |
254 | public List getSupportedPictureSizes() {
255 | if (mCamera == null) {
256 | return null;
257 | }
258 | return mCamera.getParameters().getSupportedPictureSizes();
259 | }
260 |
261 |
262 | @Override
263 | public void onPreviewFrame(byte[] nv21, Camera camera) {
264 | if (cameraListener != null) {
265 | cameraListener.onPreview(nv21, camera);
266 | }
267 | }
268 |
269 | private TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
270 | @Override
271 | public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
272 | // start();
273 | if (mCamera != null) {
274 | try {
275 | mCamera.setPreviewTexture(surfaceTexture);
276 | } catch (IOException e) {
277 | e.printStackTrace();
278 | }
279 | }
280 | }
281 |
282 | @Override
283 | public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int width, int height) {
284 | Log.i(TAG, "onSurfaceTextureSizeChanged: " + width + " " + height);
285 | }
286 |
287 | @Override
288 | public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
289 | stop();
290 | return false;
291 | }
292 |
293 | @Override
294 | public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
295 |
296 | }
297 | };
298 | private SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
299 | @Override
300 | public void surfaceCreated(SurfaceHolder holder) {
301 | // start();
302 | if (mCamera != null) {
303 | try {
304 | mCamera.setPreviewDisplay(holder);
305 | } catch (IOException e) {
306 | e.printStackTrace();
307 | }
308 | }
309 | }
310 |
311 | @Override
312 | public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
313 |
314 | }
315 |
316 | @Override
317 | public void surfaceDestroyed(SurfaceHolder holder) {
318 | stop();
319 | }
320 | };
321 |
322 | public void changeDisplayOrientation(int rotation) {
323 | if (mCamera != null) {
324 | this.rotation = rotation;
325 | displayOrientation = getCameraOri(rotation);
326 | mCamera.setDisplayOrientation(displayOrientation);
327 | if (cameraListener != null) {
328 | cameraListener.onCameraConfigurationChanged(mCameraId, displayOrientation);
329 | }
330 | }
331 | }
332 | public boolean switchCamera() {
333 | if (Camera.getNumberOfCameras() < 2) {
334 | return false;
335 | }
336 | // cameraId ,0为后置,1为前置
337 | specificCameraId = 1 - mCameraId;
338 | stop();
339 | start();
340 | return true;
341 | }
342 |
343 | public static final class Builder {
344 |
345 | /**
346 | * 预览显示的view,目前仅支持surfaceView和textureView
347 | */
348 | private View previewDisplayView;
349 |
350 | /**
351 | * 是否镜像显示,只支持textureView
352 | */
353 | private boolean isMirror;
354 | /**
355 | * 指定的相机ID
356 | */
357 | private Integer specificCameraId;
358 | /**
359 | * 事件回调
360 | */
361 | private CameraListener cameraListener;
362 | /**
363 | * 屏幕的长宽,在选择最佳相机比例时用到
364 | */
365 | private Point previewViewSize;
366 | /**
367 | * 传入getWindowManager().getDefaultDisplay().getRotation()的值即可
368 | */
369 | private int rotation;
370 | /**
371 | * 指定的预览宽高,若系统支持则会以这个预览宽高进行预览
372 | */
373 | private Point previewSize;
374 |
375 | /**
376 | * 额外的旋转角度(用于适配一些定制设备)
377 | */
378 | private int additionalRotation;
379 |
380 | public Builder() {
381 | }
382 |
383 |
384 | public Builder previewOn(View val) {
385 | if (val instanceof SurfaceView || val instanceof TextureView) {
386 | previewDisplayView = val;
387 | return this;
388 | } else {
389 | throw new RuntimeException("you must preview on a textureView or a surfaceView");
390 | }
391 | }
392 |
393 |
394 | public Builder isMirror(boolean val) {
395 | isMirror = val;
396 | return this;
397 | }
398 |
399 | public Builder previewSize(Point val) {
400 | previewSize = val;
401 | return this;
402 | }
403 |
404 | public Builder previewViewSize(Point val) {
405 | previewViewSize = val;
406 | return this;
407 | }
408 |
409 | public Builder rotation(int val) {
410 | rotation = val;
411 | return this;
412 | }
413 |
414 | public Builder additionalRotation(int val) {
415 | additionalRotation = val;
416 | return this;
417 | }
418 |
419 | public Builder specificCameraId(Integer val) {
420 | specificCameraId = val;
421 | return this;
422 | }
423 |
424 | public Builder cameraListener(CameraListener val) {
425 | cameraListener = val;
426 | return this;
427 | }
428 |
429 | public CameraHelper build() {
430 | if (previewViewSize == null) {
431 | Log.e(TAG, "previewViewSize is null, now use default previewSize");
432 | }
433 | if (cameraListener == null) {
434 | Log.e(TAG, "cameraListener is null, callback will not be called");
435 | }
436 | if (previewDisplayView == null) {
437 | throw new RuntimeException("you must preview on a textureView or a surfaceView");
438 | }
439 | return new CameraHelper(this);
440 | }
441 | }
442 |
443 | }
444 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/camera/CameraListener.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils.camera;
2 |
3 | import android.hardware.Camera;
4 |
5 |
6 | public interface CameraListener {
7 | /**
8 | * 当打开时执行
9 | * @param camera 相机实例
10 | * @param cameraId 相机ID
11 | * @param displayOrientation 相机预览旋转角度
12 | * @param isMirror 是否镜像显示
13 | */
14 | void onCameraOpened(Camera camera, int cameraId, int displayOrientation, boolean isMirror);
15 |
16 | /**
17 | * 预览数据回调
18 | * @param data 预览数据
19 | * @param camera 相机实例
20 | */
21 | void onPreview(byte[] data, Camera camera);
22 |
23 | /**
24 | * 当相机关闭时执行
25 | */
26 | void onCameraClosed();
27 |
28 | /**
29 | * 当出现异常时执行
30 | * @param e 相机相关异常
31 | */
32 | void onCameraError(Exception e);
33 |
34 | /**
35 | * 属性变化时调用
36 | * @param cameraID 相机ID
37 | * @param displayOrientation 相机旋转方向
38 | */
39 | void onCameraConfigurationChanged(int cameraID, int displayOrientation);
40 | }
41 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/face/FaceListener.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils.face;
2 |
3 |
4 | import androidx.annotation.Nullable;
5 |
6 | import com.arcsoft.face.FaceFeature;
7 | import com.arcsoft.face.LivenessInfo;
8 |
9 | /**
10 | * 人脸处理回调
11 | */
12 | public interface FaceListener {
13 | /**
14 | * 当出现异常时执行
15 | *
16 | * @param e 异常信息
17 | */
18 | void onFail(Exception e);
19 |
20 |
21 | /**
22 | * 请求人脸特征后的回调
23 | *
24 | * @param faceFeature 人脸特征数据
25 | * @param requestId 请求码
26 | * @param errorCode 错误码
27 | */
28 | void onFaceFeatureInfoGet(@Nullable FaceFeature faceFeature, Integer requestId, Integer errorCode);
29 |
30 | /**
31 | * 请求活体检测后的回调
32 | *
33 | * @param livenessInfo 活体检测结果
34 | * @param requestId 请求码
35 | * @param errorCode 错误码
36 | */
37 | void onFaceLivenessInfoGet(@Nullable LivenessInfo livenessInfo, Integer requestId, Integer errorCode);
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/face/LivenessType.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils.face;
2 |
3 | /**
4 | * 活体检测类型
5 | */
6 | public enum LivenessType {
7 | /**
8 | * RGB活体检测
9 | */
10 | RGB,
11 | /**
12 | * 红外活体检测
13 | */
14 | IR
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/face/RecognizeColor.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils.face;
2 |
3 | import android.graphics.Color;
4 |
5 | /**
6 | * 识别过程中人脸框的颜色
7 | */
8 | public class RecognizeColor {
9 | /**
10 | * 未知情况的颜色
11 | */
12 | public static final int COLOR_UNKNOWN = Color.YELLOW;
13 | /**
14 | * 成功的颜色
15 | */
16 | public static final int COLOR_SUCCESS = Color.GREEN;
17 | /**
18 | * 失败的颜色
19 | */
20 | public static final int COLOR_FAILED = Color.RED;
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/face/RequestFeatureStatus.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils.face;
2 |
3 | /**
4 | * 请求的结果状态
5 | * @author 小游
6 | */
7 | public class RequestFeatureStatus {
8 | public static final int SEARCHING = 0;
9 | public static final int SUCCEED = 1;
10 | public static final int FAILED = 2;
11 | public static final int TO_RETRY = 3;
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/utils/face/RequestLivenessStatus.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.utils.face;
2 |
3 | public class RequestLivenessStatus {
4 | public static final int ANALYZING = 10;
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/view/ColorfulMonthView.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.view;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 |
6 | import com.haibin.calendarview.Calendar;
7 | import com.haibin.calendarview.MonthView;
8 |
9 | /**
10 | * 高仿魅族日历布局
11 | * Created by huanghaibin on 2017/11/15.
12 | */
13 |
14 | public class ColorfulMonthView extends MonthView {
15 |
16 | private int mRadius;
17 |
18 | public ColorfulMonthView(Context context) {
19 | super(context);
20 | }
21 |
22 | @Override
23 | protected void onPreviewHook() {
24 | mRadius = Math.min(mItemWidth, mItemHeight) / 5 * 2;
25 | }
26 |
27 | /**
28 | * 如果需要点击Scheme没有效果,则return true
29 | *
30 | * @param canvas canvas
31 | * @param calendar 日历日历calendar
32 | * @param x 日历Card x起点坐标
33 | * @param y 日历Card y起点坐标
34 | * @param hasScheme hasScheme 非标记的日期
35 | * @return false 则不绘制onDrawScheme,因为这里背景色是互斥的
36 | */
37 | @Override
38 | protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme) {
39 | int cx = x + mItemWidth / 2;
40 | int cy = y + mItemHeight / 2;
41 | canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
42 | return true;
43 | }
44 |
45 | @Override
46 | protected void onDrawScheme(Canvas canvas, Calendar calendar, int x, int y) {
47 | int cx = x + mItemWidth / 2;
48 | int cy = y + mItemHeight / 2;
49 | canvas.drawCircle(cx, cy, mRadius, mSchemePaint);
50 | }
51 |
52 | @SuppressWarnings("IntegerDivisionInFloatingPointContext")
53 | @Override
54 | protected void onDrawText(Canvas canvas, Calendar calendar, int x, int y, boolean hasScheme, boolean isSelected) {
55 | int cx = x + mItemWidth / 2;
56 | int top = y - mItemHeight / 8;
57 | if (isSelected) {
58 | canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
59 | calendar.isCurrentDay() ? mCurDayTextPaint : mSelectTextPaint);
60 | canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
61 | calendar.isCurrentDay() ? mCurDayLunarTextPaint : mSelectedLunarTextPaint);
62 | } else if (hasScheme) {
63 | canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
64 | calendar.isCurrentDay() ? mCurDayTextPaint :
65 | calendar.isCurrentMonth() ? mSchemeTextPaint : mOtherMonthTextPaint);
66 |
67 | canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10, mSchemeLunarTextPaint);
68 | } else {
69 | canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
70 | calendar.isCurrentDay() ? mCurDayTextPaint :
71 | calendar.isCurrentMonth() ? mCurMonthTextPaint : mOtherMonthTextPaint);
72 | canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + y + mItemHeight / 10,
73 | calendar.isCurrentDay() ? mCurDayLunarTextPaint : mCurMonthLunarTextPaint);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/view/ColorfulWeekView.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.view;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 |
6 | import com.haibin.calendarview.Calendar;
7 | import com.haibin.calendarview.WeekView;
8 |
9 | /**
10 | * 多彩周视图
11 | * Created by huanghaibin on 2017/11/29.
12 | */
13 |
14 | public class ColorfulWeekView extends WeekView {
15 |
16 | private int mRadius;
17 |
18 | public ColorfulWeekView(Context context) {
19 | super(context);
20 | // //兼容硬件加速无效的代码
21 | // setLayerType(View.LAYER_TYPE_SOFTWARE, mSelectedPaint);
22 | // //4.0以上硬件加速会导致无效
23 | // mSelectedPaint.setMaskFilter(new BlurMaskFilter(30, BlurMaskFilter.Blur.SOLID));
24 | //
25 | // setLayerType(View.LAYER_TYPE_SOFTWARE, mSchemePaint);
26 | // mSchemePaint.setMaskFilter(new BlurMaskFilter(30, BlurMaskFilter.Blur.SOLID));
27 | }
28 |
29 | @Override
30 | protected void onPreviewHook() {
31 | mRadius = Math.min(mItemWidth, mItemHeight) / 5 * 2;
32 | }
33 |
34 | /**
35 | * 如果需要点击Scheme没有效果,则return true
36 | *
37 | * @param canvas canvas
38 | * @param calendar 日历日历calendar
39 | * @param x 日历Card x起点坐标
40 | * @param hasScheme hasScheme 非标记的日期
41 | * @return false 则不绘制onDrawScheme,因为这里背景色是互斥的
42 | */
43 | @Override
44 | protected boolean onDrawSelected(Canvas canvas, Calendar calendar, int x, boolean hasScheme) {
45 | int cx = x + mItemWidth / 2;
46 | int cy = mItemHeight / 2;
47 | canvas.drawCircle(cx, cy, mRadius, mSelectedPaint);
48 | return true;
49 | }
50 |
51 |
52 | @Override
53 | protected void onDrawScheme(Canvas canvas, Calendar calendar, int x) {
54 | int cx = x + mItemWidth / 2;
55 | int cy = mItemHeight / 2;
56 | canvas.drawCircle(cx, cy, mRadius, mSchemePaint);
57 | }
58 |
59 | @SuppressWarnings("IntegerDivisionInFloatingPointContext")
60 | @Override
61 | protected void onDrawText(Canvas canvas, Calendar calendar, int x, boolean hasScheme, boolean isSelected) {
62 | int cx = x + mItemWidth / 2;
63 | int top = -mItemHeight / 8;
64 | if (isSelected) {
65 | canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
66 | calendar.isCurrentDay() ? mCurDayTextPaint : mSelectTextPaint);
67 | canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
68 | calendar.isCurrentDay() ? mCurDayLunarTextPaint : mSelectedLunarTextPaint);
69 | } else if (hasScheme) {
70 | canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
71 | calendar.isCurrentDay() ? mCurDayTextPaint :
72 | calendar.isCurrentMonth() ? mSchemeTextPaint : mSchemeTextPaint);
73 |
74 | canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10, mSchemeLunarTextPaint);
75 | } else {
76 | canvas.drawText(String.valueOf(calendar.getDay()), cx, mTextBaseLine + top,
77 | calendar.isCurrentDay() ? mCurDayTextPaint :
78 | calendar.isCurrentMonth() ? mCurMonthTextPaint : mCurMonthTextPaint);
79 | canvas.drawText(calendar.getLunar(), cx, mTextBaseLine + mItemHeight / 10,
80 | calendar.isCurrentDay() ? mCurDayLunarTextPaint : mCurMonthLunarTextPaint);
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/widget/FaceRectView.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.widget;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Paint;
6 |
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 |
10 |
11 | import androidx.annotation.Nullable;
12 |
13 | import com.xiaoyou.face.model.DrawInfo;
14 | import com.xiaoyou.face.utils.DrawHelper;
15 |
16 | import java.util.List;
17 | import java.util.concurrent.CopyOnWriteArrayList;
18 |
19 | /**
20 | * 用于显示人脸信息的控件
21 | */
22 | public class FaceRectView extends View {
23 | private CopyOnWriteArrayList drawInfoList = new CopyOnWriteArrayList<>();
24 |
25 | // 画笔,复用
26 | private Paint paint;
27 |
28 | // 默认人脸框厚度
29 | private static final int DEFAULT_FACE_RECT_THICKNESS = 6;
30 |
31 | public FaceRectView(Context context) {
32 | this(context, null);
33 | }
34 |
35 | public FaceRectView(Context context, @Nullable AttributeSet attrs) {
36 | super(context, attrs);
37 | paint = new Paint();
38 | }
39 |
40 | @Override
41 | protected void onDraw(Canvas canvas) {
42 | super.onDraw(canvas);
43 | if (drawInfoList != null && drawInfoList.size() > 0) {
44 | for (int i = 0; i < drawInfoList.size(); i++) {
45 | DrawHelper.drawFaceRect(canvas, drawInfoList.get(i), DEFAULT_FACE_RECT_THICKNESS, paint);
46 | }
47 | }
48 | }
49 |
50 | public void clearFaceInfo() {
51 | drawInfoList.clear();
52 | postInvalidate();
53 | }
54 |
55 | public void addFaceInfo(DrawInfo faceInfo) {
56 | drawInfoList.add(faceInfo);
57 | postInvalidate();
58 | }
59 |
60 | public void addFaceInfo(List faceInfoList) {
61 | drawInfoList.addAll(faceInfoList);
62 | postInvalidate();
63 | }
64 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/xiaoyou/face/widget/FaceSearchResultAdapter.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face.widget;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.view.ViewGroup;
8 | import android.widget.ImageView;
9 | import android.widget.TextView;
10 |
11 |
12 | import androidx.annotation.NonNull;
13 | import androidx.recyclerview.widget.RecyclerView;
14 |
15 | import com.bumptech.glide.Glide;
16 | import com.xiaoyou.face.R;
17 | import com.xiaoyou.face.faceserver.CompareResult;
18 | import com.xiaoyou.face.faceserver.FaceServer;
19 |
20 | import java.io.File;
21 | import java.util.List;
22 |
23 | /**
24 | * 人脸搜索显示的adapter
25 | * @author 小游
26 | * @date 2020/11/16
27 | */
28 | public class FaceSearchResultAdapter extends RecyclerView.Adapter {
29 | private final List compareResultList;
30 | private final LayoutInflater inflater;
31 |
32 | public FaceSearchResultAdapter(List compareResultList, Context context) {
33 | inflater = LayoutInflater.from(context);
34 | this.compareResultList = compareResultList;
35 | }
36 |
37 |
38 | @NonNull
39 | @Override
40 | public CompareResultHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
41 | // 这里我们查找控件并注册
42 | View itemView = inflater.inflate(R.layout.recycler_item_search_result, null, false);
43 | CompareResultHolder compareResultHolder = new CompareResultHolder(itemView);
44 | compareResultHolder.textView = itemView.findViewById(R.id.tv_item_name);
45 | compareResultHolder.textNo = itemView.findViewById(R.id.tv_item_no);
46 | compareResultHolder.textBelieve = itemView.findViewById(R.id.tv_item_believe);
47 | compareResultHolder.imageView = itemView.findViewById(R.id.iv_item_head_img);
48 | return compareResultHolder;
49 | }
50 |
51 | @SuppressLint("SetTextI18n")
52 | @Override
53 | public void onBindViewHolder(@NonNull CompareResultHolder holder, int position) {
54 | if (compareResultList == null) {
55 | return;
56 | }
57 |
58 | // 这里我们加载图片并显示(我们这里使用学号来存储图片)
59 | File imgFile = new File(FaceServer.ROOT_PATH + File.separator + FaceServer.SAVE_IMG_DIR + File.separator + compareResultList.get(position).getId() + FaceServer.IMG_SUFFIX);
60 | Glide.with(holder.imageView)
61 | .load(imgFile)
62 | .into(holder.imageView);
63 |
64 | // 这里我们显示学号和姓名
65 | holder.textView.setText("姓名:"+compareResultList.get(position).getUserName());
66 | holder.textNo.setText("学号:"+compareResultList.get(position).getUserNo());
67 | holder.textBelieve.setText("相似度:"+compareResultList.get(position).getSimilar());
68 | }
69 |
70 | @Override
71 | public int getItemCount() {
72 | return compareResultList == null ? 0 : compareResultList.size();
73 | }
74 |
75 | static class CompareResultHolder extends RecyclerView.ViewHolder {
76 | TextView textView;
77 | TextView textNo;
78 | TextView textBelieve;
79 | ImageView imageView;
80 | CompareResultHolder(@NonNull View itemView) {
81 | super(itemView);
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/src/main/jniLibs/arm64-v8a/libarcsoft_face.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/jniLibs/arm64-v8a/libarcsoft_face.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/arm64-v8a/libarcsoft_face_engine.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/jniLibs/arm64-v8a/libarcsoft_face_engine.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/arm64-v8a/libarcsoft_image_util.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/jniLibs/arm64-v8a/libarcsoft_image_util.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libarcsoft_face.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/jniLibs/armeabi-v7a/libarcsoft_face.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libarcsoft_face_engine.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/jniLibs/armeabi-v7a/libarcsoft_face_engine.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libarcsoft_image_util.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/jniLibs/armeabi-v7a/libarcsoft_image_util.so
--------------------------------------------------------------------------------
/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_add_reaction.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_arrow_back.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_calendar.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_camera.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_close.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_credit.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_face.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_faces_white.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_photo_camera.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_pie_chart.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_search_white.xml:
--------------------------------------------------------------------------------
1 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_switch_camera.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable/ic_tool_box.xml:
--------------------------------------------------------------------------------
1 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
14 |
15 |
16 |
17 |
22 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_register_and_recognize.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
19 |
22 |
25 |
29 |
30 |
34 |
35 |
45 |
46 |
47 |
55 |
56 |
57 |
58 |
59 |
60 |
64 |
65 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_sign_detail.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
21 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/dialog_input.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
13 |
19 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_index.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
17 |
18 |
19 |
29 |
30 |
40 |
41 |
49 |
50 |
59 |
60 |
61 |
62 |
69 |
70 |
77 |
78 |
88 |
89 |
90 |
91 |
92 |
99 |
100 |
126 |
127 |
128 |
129 |
136 |
137 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_me.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
15 |
22 |
23 |
24 |
28 |
29 |
36 |
37 |
47 |
48 |
56 |
57 |
58 |
63 |
64 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/fragment_tool.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
14 |
21 |
22 |
23 |
33 |
36 |
37 |
41 |
42 |
46 |
47 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/include_close_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
12 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/item_grid.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
14 |
15 |
20 |
21 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/recycler_item_search_result.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
14 |
15 |
16 |
21 |
22 |
27 |
28 |
33 |
34 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-hdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-mdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/face.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xxhdpi/face.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xxhdpi/login.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xxhdpi/search.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/statistics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xxhdpi/statistics.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
17 |
23 |
--------------------------------------------------------------------------------
/app/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - 学号
5 | - 姓名
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
11 | #67C23A
12 | #E6A23C
13 | #F56C6C
14 | #909399
15 | #409EFF
16 | #53A8FF
17 |
18 | #E8EAED
19 |
20 | #efefef
21 |
22 |
23 | #80000000
24 | #80000000
25 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 12dp
4 | 6dp
5 | 20dp
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFFFFF
4 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | 刷脸签到
3 | Hello blank fragment
4 |
5 |
6 | 录入
7 | 取消
8 | 学号
9 | 姓名
10 | 人脸录入
11 |
12 |
13 | 考勤统计
14 |
15 |
16 | 关键词
17 | 搜索
18 |
19 |
20 |
21 | 人脸属性检测(视频)
22 | 红外活体检测(视频)
23 | 人脸比对1:n(视频vs人脸库,RGB活体)
24 | 人脸比对1:n(视频vs人脸库,IR活体)
25 | 人脸属性检测(图片)
26 | 人脸比对1:n(图片vs图片)
27 | 人脸批量注册管理
28 | 获取设备指纹失败,错误码:%d
29 | 选择视频模式检测角度
30 | 复制设备指纹信息
31 | 设备指纹信息:\n%s\n已复制
32 | 激活引擎
33 | 激活引擎成功
34 | 引擎已激活,无需再次激活
35 | 引擎激活失败,错误码为 %d
36 | 未找到库文件,请检查是否有将.so文件放至工程的 app\\src\\main\\jniLibs 目录下
37 | 视频模式仅检测0度
38 | 视频模式仅检测90度
39 | 视频模式仅检测180度
40 | 视频模式仅检测270度
41 | 视频模式全方向人脸检测
42 |
43 |
44 | 开始处理
45 | 选择本地图片
46 | 处理中
47 |
48 |
49 | 选择主图
50 | 添加比对图
51 | 请先选择主图
52 | 比对失败,错误码为 %d
53 |
54 |
55 | 获取图片失败
56 |
57 |
58 | 权限被拒绝!
59 |
60 |
61 | 引擎初始化失败,错误码为 %d
62 | 引擎未初始化,错误码为 %d
63 |
64 |
65 | 注册
66 | 切换相机
67 | 切换相机失败
68 | 未通过:%s
69 | [%s]签到成功!
70 | [%s]已签到!
71 | [%s]已注册!
72 | 人脸置信度低
73 | %s 初始化失败,错误码为:%d
74 | 相机已切换,若无法检测到人脸,需要在首页修改视频模式人脸检测角度
75 | 活体检测
76 | RGB CAMERA
77 | IR CAMERA
78 | RGB CAMERA\n%dx%d
79 | IR CAMERA\n%dx%d
80 | \n可能的原因:该设备不支持同时打开两个摄像头
81 | IR人脸框水平镜像绘制
82 | IR人脸框垂直镜像绘制
83 |
84 |
85 | 进度: %d / %d
86 | 注册中,请稍等
87 |
88 |
89 | 确认
90 | 取消
91 | 请将需要注册的图片放在\nsdcard/arcfacedemo/register\n目录下
92 | 无人脸需要删除
93 | 确认删除这%d张图片及人脸特征?
94 | 批量注册
95 | 提示
96 | 清空人脸库
97 | 路径 \n%s\n 不存在
98 | 路径 \n%s\n 不是文件夹
99 | 处理中,请稍等
100 | 处理完成!\n处理总数 = %d \n成功数 = %d \n失败数 = %d \n处理失败的图片已保存在文件夹 \' %s \'
101 | 数据统计
102 |
103 |
104 |
--------------------------------------------------------------------------------
/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
13 |
26 |
--------------------------------------------------------------------------------
/app/src/main/res/xml/file_paths_public.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/test/java/com/xiaoyou/face/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.xiaoyou.face;
2 |
3 | import com.xiaoyou.face.service.StudentInfo;
4 | import com.xiaoyou.face.utils.FaceRead;
5 |
6 | import org.junit.Test;
7 |
8 | import java.time.LocalDate;
9 | import java.time.LocalDateTime;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Example local unit test, which will execute on the development machine (host).
15 | *
16 | * @see Testing documentation
17 | */
18 | public class ExampleUnitTest {
19 | @Test
20 | public void addition_isCorrect() {
21 | assertEquals(4, 2 + 2);
22 | }
23 |
24 | @Test
25 | public void faceTest() throws Exception {
26 | //FaceRead.checkFace("D:\\tmp\\2.jpg");
27 | StudentInfo studentInfo = new StudentInfo();
28 | studentInfo.setDateTime(LocalDate.now());
29 | System.out.println(studentInfo.getDateTime().getMonthValue());
30 | }
31 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | google()
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath "com.android.tools.build:gradle:4.1.1"
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | google()
18 | jcenter()
19 | maven { url "https://jitpack.io" }
20 | mavenCentral()
21 | }
22 | }
23 |
24 | task clean(type: Delete) {
25 | delete rootProject.buildDir
26 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Mon Dec 14 12:02:12 CST 2020
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/image/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/image/1.jpg
--------------------------------------------------------------------------------
/image/2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/image/2.jpg
--------------------------------------------------------------------------------
/image/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/image/2.png
--------------------------------------------------------------------------------
/image/3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/image/3.jpg
--------------------------------------------------------------------------------
/image/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/image/3.png
--------------------------------------------------------------------------------
/image/4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/image/4.jpg
--------------------------------------------------------------------------------
/image/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xiaoyou-project/android-course-design/caddcbae0cd19af083382942f34f1f1d2754fcbd/image/4.png
--------------------------------------------------------------------------------
/lombok.config:
--------------------------------------------------------------------------------
1 | lombok.anyConstructor.suppressConstructorProperties=true
2 | config.stopBubbling=true
3 | lombok.equalsAndHashCode.callSuper=call
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 | rootProject.name = "face"
--------------------------------------------------------------------------------