feat(activity): 新增菜品识别功能,重构FoodRecognizeDialog并临时跳过调料配置检查
- 新增 FoodRecognizeDialog(继承 BottomSheetDialog),只初始化一次,暴露 loadData() 方法 - 新增 dialog_food_recognize.xml 布局(标题 + 2列 GridLayoutManager RecyclerView) - PrepareCookActivity 集成相机初始化、拍照识别流程(重量稳定 ≥10g 时触发) - PrepareCookActivity 新增 flCameraContainer(1dp 隐藏容器)用于相机预览绑定 - SelectDishActivity 临时注释 judgeDeviceConfig 逻辑,直接调用 block() - 修正 GpioUtils/L/LightManager 包名为 com.shuwei.dish.match.utils
This commit is contained in:
@@ -41,6 +41,7 @@ class GoodsInfoSearchAdapter(private var list: MutableList<CookFoodGoodsEntity>)
|
|||||||
): VH {
|
): VH {
|
||||||
val binding =
|
val binding =
|
||||||
ListItemSearchGoodsInfoBinding.inflate(LayoutInflater.from(context), parent, false)
|
ListItemSearchGoodsInfoBinding.inflate(LayoutInflater.from(context), parent, false)
|
||||||
|
|
||||||
return VH(binding)
|
return VH(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.shuwei.dish.match.dialog
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
|
import com.shuwei.dish.match.R
|
||||||
|
import com.shuwei.dish.match.adapter.GoodsInfoSearchAdapter
|
||||||
|
import com.shuwei.dish.match.base.BaseActivity
|
||||||
|
import com.shuwei.dish.match.databinding.DialogFoodRecognizeBinding
|
||||||
|
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 菜品识别结果弹窗,继承 BottomSheetDialog 确保只初始化一次
|
||||||
|
* @param activity 宿主 Activity
|
||||||
|
* @param onItemSelected 用户点击某一菜品时的回调
|
||||||
|
*/
|
||||||
|
class FoodRecognizeDialog(
|
||||||
|
private val activity: BaseActivity,
|
||||||
|
private val onItemSelected: (item: CookFoodGoodsEntity) -> Unit
|
||||||
|
) : BottomSheetDialog(activity, R.style.BottomSheet) {
|
||||||
|
|
||||||
|
private val binding = DialogFoodRecognizeBinding.inflate(LayoutInflater.from(activity))
|
||||||
|
private val list = mutableListOf<CookFoodGoodsEntity>()
|
||||||
|
private val adapter = GoodsInfoSearchAdapter(list).apply {
|
||||||
|
setOnItemClickListener { _, _, position ->
|
||||||
|
list[position].isClicked = true
|
||||||
|
notifyItemChanged(position)
|
||||||
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
|
onItemSelected(list[position])
|
||||||
|
dismiss()
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
setContentView(binding.root)
|
||||||
|
setCancelable(true)
|
||||||
|
behavior.skipCollapsed = false
|
||||||
|
setOnDismissListener { activity.hideStatusBar() }
|
||||||
|
binding.recyclerView.run {
|
||||||
|
layoutManager = GridLayoutManager(activity, 2, GridLayoutManager.VERTICAL, false)
|
||||||
|
adapter = this@FoodRecognizeDialog.adapter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加载识别结果数据并显示弹窗
|
||||||
|
* @param items 识别到的菜品列表
|
||||||
|
*/
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun loadData(items: List<CookFoodGoodsEntity>) {
|
||||||
|
list.clear()
|
||||||
|
list.addAll(items)
|
||||||
|
adapter.notifyDataSetChanged()
|
||||||
|
if (!isShowing) show()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
package com.shuwei.dish.match.ui
|
package com.shuwei.dish.match.ui
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.graphics.Bitmap
|
||||||
import android.graphics.Typeface
|
import android.graphics.Typeface
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.activity.viewModels
|
|
||||||
import androidx.recyclerview.widget.ItemTouchHelper
|
import androidx.recyclerview.widget.ItemTouchHelper
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.shuwei.dish.match.R
|
import com.shuwei.dish.match.R
|
||||||
@@ -12,23 +13,34 @@ import com.shuwei.dish.match.adapter.DishPartAdapter
|
|||||||
import com.shuwei.dish.match.base.BaseActivity
|
import com.shuwei.dish.match.base.BaseActivity
|
||||||
import com.shuwei.dish.match.databinding.ActivityPrepareCookBinding
|
import com.shuwei.dish.match.databinding.ActivityPrepareCookBinding
|
||||||
import com.shuwei.dish.match.databinding.LayoutFoodRemindBinding
|
import com.shuwei.dish.match.databinding.LayoutFoodRemindBinding
|
||||||
import com.shuwei.dish.match.dialog.FoodSearchDialog
|
|
||||||
import com.shuwei.dish.match.dialog.CommonDialog
|
import com.shuwei.dish.match.dialog.CommonDialog
|
||||||
|
import com.shuwei.dish.match.dialog.FoodRecognizeDialog
|
||||||
|
import com.shuwei.dish.match.dialog.FoodSearchDialog
|
||||||
import com.shuwei.dish.match.entity.CookFoodEntity
|
import com.shuwei.dish.match.entity.CookFoodEntity
|
||||||
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
import com.shuwei.dish.match.entity.CookFoodGoodsEntity
|
||||||
import com.shuwei.dish.match.entity.FoodRecord
|
import com.shuwei.dish.match.entity.FoodRecord
|
||||||
import com.shuwei.dish.match.net.NetViewModel
|
import android.view.ViewGroup
|
||||||
|
import androidx.camera.view.PreviewView
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import com.shuwei.dish.match.databinding.LayoutCameraPreviewBinding
|
||||||
|
import com.shuwei.dish.match.objbox.FoodModule
|
||||||
import com.shuwei.dish.match.utils.AddressUtil
|
import com.shuwei.dish.match.utils.AddressUtil
|
||||||
|
import com.shuwei.dish.match.utils.CameraUtils
|
||||||
|
import com.shuwei.dish.match.utils.ImageUtil
|
||||||
import com.shuwei.dish.match.utils.SwipeCallback
|
import com.shuwei.dish.match.utils.SwipeCallback
|
||||||
import com.shuwei.dish.match.utils.WeightUtil
|
import com.shuwei.dish.match.utils.WeightUtil
|
||||||
import com.shuwei.dish.match.utils.ext.clickWithDebounce
|
import com.shuwei.dish.match.utils.ext.clickWithDebounce
|
||||||
import com.shuwei.dish.match.utils.ext.gone
|
import com.shuwei.dish.match.utils.ext.gone
|
||||||
|
import com.shuwei.dish.match.utils.ext.roundedDecimalPlace
|
||||||
import com.shuwei.dish.match.utils.ext.startActivity
|
import com.shuwei.dish.match.utils.ext.startActivity
|
||||||
import com.shuwei.dish.match.utils.ext.toJsonString
|
import com.shuwei.dish.match.utils.ext.toJsonString
|
||||||
import com.shuwei.dish.match.utils.ext.toast
|
import com.shuwei.dish.match.utils.ext.toast
|
||||||
import com.shuwei.dish.match.utils.ext.visible
|
import com.shuwei.dish.match.utils.ext.visible
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import kotlin.getValue
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
@SuppressLint("NotifyDataSetChanged")
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
class PrepareCookActivity : BaseActivity() {
|
class PrepareCookActivity : BaseActivity() {
|
||||||
@@ -40,6 +52,8 @@ class PrepareCookActivity : BaseActivity() {
|
|||||||
|
|
||||||
private lateinit var binding: ActivityPrepareCookBinding
|
private lateinit var binding: ActivityPrepareCookBinding
|
||||||
|
|
||||||
|
private val cameraUtils: CameraUtils by lazy { CameraUtils(this) }
|
||||||
|
|
||||||
private var food: FoodRecord? = null
|
private var food: FoodRecord? = null
|
||||||
|
|
||||||
private var goodsList: MutableList<CookFoodGoodsEntity>? = null
|
private var goodsList: MutableList<CookFoodGoodsEntity>? = null
|
||||||
@@ -69,6 +83,7 @@ class PrepareCookActivity : BaseActivity() {
|
|||||||
binding.tvDishName.text = food?.foodName ?: ""
|
binding.tvDishName.text = food?.foodName ?: ""
|
||||||
addViewClickListener()
|
addViewClickListener()
|
||||||
|
|
||||||
|
initCamera(binding.flCameraContainer)
|
||||||
initRecyclerView()
|
initRecyclerView()
|
||||||
|
|
||||||
getDishDetail()
|
getDishDetail()
|
||||||
@@ -81,6 +96,9 @@ class PrepareCookActivity : BaseActivity() {
|
|||||||
//Log.d(TAG, "addViewClickListener: address=$address,state=$state,weight=$weight")
|
//Log.d(TAG, "addViewClickListener: address=$address,state=$state,weight=$weight")
|
||||||
if (address == AddressUtil.ONE) {
|
if (address == AddressUtil.ONE) {
|
||||||
binding.tvDishPartWeight.text = "${weight}"
|
binding.tvDishPartWeight.text = "${weight}"
|
||||||
|
if (state == WeightUtil.STATE_STABLE) {
|
||||||
|
recognizeFood(weight)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
binding.ivWeightClear.setOnClickListener {
|
binding.ivWeightClear.setOnClickListener {
|
||||||
@@ -134,6 +152,25 @@ class PrepareCookActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val isTakingPhoto = AtomicBoolean(false)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重量稳定时触发菜品识别
|
||||||
|
* @param weight 当前稳定重量
|
||||||
|
*/
|
||||||
|
private fun recognizeFood(weight: Double) {
|
||||||
|
if (weight < 10) {
|
||||||
|
if (recognizeDialog.isShowing) recognizeDialog.dismiss()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (isTakingPhoto.get() || recognizeDialog.isShowing) return
|
||||||
|
isTakingPhoto.set(true)
|
||||||
|
cameraUtils.takePhoto(
|
||||||
|
succCallback = cameraSuccessCallback,
|
||||||
|
failCallback = cameraFailureCallback
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun addFood() {
|
private fun addFood() {
|
||||||
FoodSearchDialog().show(this) { item ->
|
FoodSearchDialog().show(this) { item ->
|
||||||
val filterResult = list.firstOrNull { it.goodsId == item.goodsId }
|
val filterResult = list.firstOrNull { it.goodsId == item.goodsId }
|
||||||
@@ -251,6 +288,16 @@ class PrepareCookActivity : BaseActivity() {
|
|||||||
|
|
||||||
private var firstReqSize = 0
|
private var firstReqSize = 0
|
||||||
private val list = mutableListOf<CookFoodGoodsEntity>()
|
private val list = mutableListOf<CookFoodGoodsEntity>()
|
||||||
|
private val recognizeDialog by lazy {
|
||||||
|
FoodRecognizeDialog(this) { item ->
|
||||||
|
// TODO: 处理识别结果选中
|
||||||
|
}
|
||||||
|
.apply {
|
||||||
|
setOnDismissListener {
|
||||||
|
isTakingPhoto.set(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
private val dishPartAdapter by lazy {
|
private val dishPartAdapter by lazy {
|
||||||
DishPartAdapter(list).apply {
|
DishPartAdapter(list).apply {
|
||||||
setOnItemClickListener { _, _, positon ->
|
setOnItemClickListener { _, _, positon ->
|
||||||
@@ -326,6 +373,26 @@ class PrepareCookActivity : BaseActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
cameraUtils.bind()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
cameraUtils.unbind()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化相机并绑定预览容器
|
||||||
|
* @param container 相机预览容器
|
||||||
|
*/
|
||||||
|
fun initCamera(container: ViewGroup) {
|
||||||
|
cameraUtils.initCamera()
|
||||||
|
val previewBinding = LayoutCameraPreviewBinding.inflate(layoutInflater, container)
|
||||||
|
cameraUtils.setPreviewController(previewBinding.previewView)
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
@SuppressLint("GestureBackNavigation")
|
@SuppressLint("GestureBackNavigation")
|
||||||
@Deprecated("Deprecated in Java")
|
@Deprecated("Deprecated in Java")
|
||||||
@@ -367,4 +434,49 @@ class PrepareCookActivity : BaseActivity() {
|
|||||||
}.show()
|
}.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val cameraSuccessCallback: (Uri) -> Unit = { uri ->
|
||||||
|
Log.d(TAG, "takePhoto success")
|
||||||
|
lifecycleScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val bitmap = ImageUtil.uriToBitmap(this@PrepareCookActivity, uri)
|
||||||
|
if (bitmap == null) {
|
||||||
|
Log.d(TAG, "takePhoto bitmap is null")
|
||||||
|
isTakingPhoto.set(false)
|
||||||
|
return@withContext
|
||||||
|
}
|
||||||
|
val foodScoreList = FoodModule.getFoodScoreList(bitmap)
|
||||||
|
if (foodScoreList.isEmpty()) {
|
||||||
|
Log.d(TAG, "takePhoto foodScoreList is empty")
|
||||||
|
isTakingPhoto.set(false)
|
||||||
|
return@withContext
|
||||||
|
}
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
queryFood(foodScoreList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val cameraFailureCallback: (String) -> Unit = { errMsg ->
|
||||||
|
Log.d(TAG, "takePhoto failure")
|
||||||
|
isTakingPhoto.set(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun queryFood(list: List<FoodModule.IdNameScore>) {
|
||||||
|
Log.d(TAG, "takePhoto queryFood, list=${list.toString()}")
|
||||||
|
//调用接口成功,返回食材列表设置isTakingPhoto.set(false),暂时写死数据
|
||||||
|
val foodList = mutableListOf<CookFoodGoodsEntity>()
|
||||||
|
list.forEachIndexed { index, food ->
|
||||||
|
val foodName = food.name.split("WP").first()
|
||||||
|
val foodScore = ((1-food.score) * 100).roundedDecimalPlace(2)
|
||||||
|
foodList.add(CookFoodGoodsEntity(
|
||||||
|
goodsId = index.toString(),
|
||||||
|
goodsName = "${foodName}-${foodScore}%",
|
||||||
|
foodId = index.toString()
|
||||||
|
))
|
||||||
|
}
|
||||||
|
recognizeDialog.loadData(foodList)
|
||||||
|
isTakingPhoto.set(false)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -82,18 +82,19 @@ class SelectDishActivity : BaseActivity() {
|
|||||||
private var configFinished = false
|
private var configFinished = false
|
||||||
|
|
||||||
fun judgeDeviceConfig(block: () -> Unit) {
|
fun judgeDeviceConfig(block: () -> Unit) {
|
||||||
if (configFinished) {
|
// if (configFinished) {
|
||||||
|
// block()
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// appViewModel.loadSeasoning {
|
||||||
|
// if (it.isEmpty()) {
|
||||||
|
// showDeviceConfigDialog()
|
||||||
|
// return@loadSeasoning
|
||||||
|
// }
|
||||||
|
// configFinished = true
|
||||||
|
// block()
|
||||||
|
// }
|
||||||
block()
|
block()
|
||||||
return
|
|
||||||
}
|
|
||||||
appViewModel.loadSeasoning {
|
|
||||||
if (it.isEmpty()) {
|
|
||||||
showDeviceConfigDialog()
|
|
||||||
return@loadSeasoning
|
|
||||||
}
|
|
||||||
configFinished = true
|
|
||||||
block()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showDeviceConfigDialog() {
|
private fun showDeviceConfigDialog() {
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
package com.shuwei.dish.match.utils;
|
||||||
|
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.DataOutputStream;
|
||||||
|
import java.io.FileReader;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Administrator on 2018/11/9.
|
||||||
|
*/
|
||||||
|
public class GpioUtils {
|
||||||
|
|
||||||
|
private static final String TAG = "GpioUtils";
|
||||||
|
|
||||||
|
/*
|
||||||
|
给export申请权限
|
||||||
|
*/
|
||||||
|
public static void upgradeRootPermissionForExport() {
|
||||||
|
upgradeRootPermission("/sys/class/gpio/export");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
配置一个gpio路径
|
||||||
|
*/
|
||||||
|
public static boolean exportGpio(int gpio) {
|
||||||
|
return writeNode("/sys/class/gpio/export", "" + gpio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
给获取io口的状态的路径申请权限,该方法需要在exportGpio后调用
|
||||||
|
*/
|
||||||
|
public static void upgradeRootPermissionForGpio(int gpio) {
|
||||||
|
upgradeRootPermission("/sys/class/gpio/gpio" + gpio + "/direction");
|
||||||
|
upgradeRootPermission("/sys/class/gpio/gpio" + gpio + "/value");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
设置io口为输入或输出
|
||||||
|
*/
|
||||||
|
public static boolean setGpioDirection(int gpio, int arg) {
|
||||||
|
String gpioDirection = "";
|
||||||
|
if (arg == 0) gpioDirection = "out";
|
||||||
|
else if (arg == 1) gpioDirection = "in";
|
||||||
|
else return false;
|
||||||
|
return writeNode("/sys/class/gpio/gpio" + gpio + "/direction", gpioDirection);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
获取io口的状态为输出还是输入
|
||||||
|
*/
|
||||||
|
public static String getGpioDirection(int gpio) {
|
||||||
|
String gpioDirection = "";
|
||||||
|
gpioDirection = readNode("/sys/class/gpio/gpio" + gpio + "/direction");
|
||||||
|
return gpioDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
给输出io口写值,高电平或低电平
|
||||||
|
*/
|
||||||
|
public static boolean writeGpioValue(int gpio, String arg) {
|
||||||
|
return writeNode("/sys/class/gpio/gpio" + gpio + "/value", arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//获取当前gpio是高还是低
|
||||||
|
public static String getGpioValue(int gpio) {
|
||||||
|
return readNode("/sys/class/gpio/gpio" + gpio + "/value");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static boolean upgradeRootPermission(String path) {
|
||||||
|
Process process = null;
|
||||||
|
DataOutputStream os = null;
|
||||||
|
try {
|
||||||
|
String cmd = "chmod 777 " + path;
|
||||||
|
process = Runtime.getRuntime().exec("su"); //切换到root帐号
|
||||||
|
os = new DataOutputStream(process.getOutputStream());
|
||||||
|
os.writeBytes(cmd + "\n");
|
||||||
|
os.writeBytes("exit\n");
|
||||||
|
os.flush();
|
||||||
|
process.waitFor();
|
||||||
|
} catch (Exception e) {
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (os != null) {
|
||||||
|
os.close();
|
||||||
|
}
|
||||||
|
process.destroy();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return process.waitFor() == 0;
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean writeNode(String path, String arg) {
|
||||||
|
Log.d(TAG, "Gpio_test set node path: " + path + " arg: " + arg);
|
||||||
|
if (path == null || arg == null) {
|
||||||
|
Log.e(TAG, "set node error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FileWriter fileWriter = null;
|
||||||
|
BufferedWriter bufferedWriter = null;
|
||||||
|
try {
|
||||||
|
fileWriter = new FileWriter(path);
|
||||||
|
fileWriter.write(arg);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, "Gpio_test write node error!! path" + path + " arg: " + arg);
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (fileWriter != null) {
|
||||||
|
fileWriter.close();
|
||||||
|
}
|
||||||
|
if (bufferedWriter != null) {
|
||||||
|
bufferedWriter.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long mTime = 0;
|
||||||
|
private static int mFailTimes = 0;
|
||||||
|
|
||||||
|
private static String readNode(String path) {
|
||||||
|
String result = "";
|
||||||
|
|
||||||
|
FileReader fread = null;
|
||||||
|
BufferedReader buffer = null;
|
||||||
|
try {
|
||||||
|
fread = new FileReader(path);
|
||||||
|
buffer = new BufferedReader(fread);
|
||||||
|
String str = null;
|
||||||
|
while ((str = buffer.readLine()) != null) {
|
||||||
|
result = str;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mFailTimes = 0;
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.e(TAG, "IO Exception");
|
||||||
|
e.printStackTrace();
|
||||||
|
if (mTime == 0 || SystemClock.uptimeMillis() - mTime < 1000) {
|
||||||
|
mFailTimes++;
|
||||||
|
}
|
||||||
|
if (mFailTimes >= 3) {
|
||||||
|
Log.d(TAG, "read format node continuous failed three times, exist thread");
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (buffer != null) {
|
||||||
|
buffer.close();
|
||||||
|
}
|
||||||
|
if (fread != null) {
|
||||||
|
fread.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.shuwei.dish.match.utils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log统一管理类
|
||||||
|
*/
|
||||||
|
public class L {
|
||||||
|
|
||||||
|
private L() {
|
||||||
|
/* cannot be instantiated */
|
||||||
|
throw new UnsupportedOperationException("cannot be instantiated");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isDebug = true;// 是否需要打印bug,可以在application的onCreate函数里面初始化
|
||||||
|
private static final String TAG = "mzf";
|
||||||
|
|
||||||
|
// 下面四个是默认tag的函数
|
||||||
|
public static void i(String msg) {
|
||||||
|
if (isDebug)
|
||||||
|
android.util.Log.i(TAG, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void d(String msg) {
|
||||||
|
if (isDebug)
|
||||||
|
android.util.Log.d(TAG, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void e(String msg) {
|
||||||
|
if (isDebug)
|
||||||
|
android.util.Log.e(TAG, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void v(String msg) {
|
||||||
|
if (isDebug)
|
||||||
|
android.util.Log.v(TAG, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下面是传入自定义tag的函数
|
||||||
|
public static void i(String tag, String msg) {
|
||||||
|
if (isDebug)
|
||||||
|
android.util.Log.i(tag, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void d(String tag, String msg) {
|
||||||
|
if (isDebug)
|
||||||
|
android.util.Log.d(tag, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void e(String tag, String msg) {
|
||||||
|
if (isDebug)
|
||||||
|
android.util.Log.e(tag, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void v(String tag, String msg) {
|
||||||
|
if (isDebug)
|
||||||
|
android.util.Log.v(tag, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package com.shuwei.dish.match.utils;
|
||||||
|
|
||||||
|
public class LightManager {
|
||||||
|
private static final String TAG = "LightManager";
|
||||||
|
|
||||||
|
public static void openGreenLight() {
|
||||||
|
L.e(TAG, "openGreenLight");
|
||||||
|
GpioUtils.writeGpioValue(41, "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void closeGreenLight() {
|
||||||
|
L.e(TAG, "closeGreenLight");
|
||||||
|
GpioUtils.writeGpioValue(41, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void openRedLight() {
|
||||||
|
L.e(TAG, "openRedLight");
|
||||||
|
GpioUtils.writeGpioValue(40, "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void closeRedLight() {
|
||||||
|
L.e(TAG, "closeRedLight");
|
||||||
|
GpioUtils.writeGpioValue(40, "0");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -262,6 +262,11 @@
|
|||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/flCameraContainer"
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="1dp" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatButton
|
<androidx.appcompat.widget.AppCompatButton
|
||||||
android:id="@+id/btnCook"
|
android:id="@+id/btnCook"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:background="@color/white">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/viewLine"
|
||||||
|
android:layout_width="90dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_marginTop="30dp"
|
||||||
|
android:background="@drawable/shape_gray_dc_5" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvSheetName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="50dp"
|
||||||
|
android:text="菜品识别结果"
|
||||||
|
android:textColor="@color/black333"
|
||||||
|
android:textSize="36sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recyclerView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="45dp"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:layout_marginEnd="45dp"
|
||||||
|
android:layout_marginBottom="15dp"
|
||||||
|
android:minHeight="500dp"
|
||||||
|
android:nestedScrollingEnabled="true"
|
||||||
|
android:overScrollMode="never"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||||
|
app:spanCount="2"
|
||||||
|
tools:itemCount="10"
|
||||||
|
tools:listitem="@layout/list_item_search_goods_info" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
Reference in New Issue
Block a user