增加初始化功能

This commit is contained in:
2025-09-11 16:09:07 +08:00
parent e153f3e3b9
commit a355828bab
21 changed files with 1286 additions and 57 deletions
+2
View File
@@ -55,6 +55,8 @@ dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.android.core)
implementation(libs.core)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
+8 -3
View File
@@ -3,6 +3,8 @@
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.USB_PERMISSION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission
@@ -16,15 +18,15 @@
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:icon="@mipmap/ic_logo512"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:roundIcon="@mipmap/ic_logo512"
android:supportsRtl="true"
android:theme="@style/Theme.IntelligentShelves"
android:usesCleartextTraffic="true">
<activity
android:name=".HomeActivity"
android:name=".InitActivity"
android:exported="true"
android:screenOrientation="portrait"
tools:ignore="DiscouragedApi,LockedOrientationActivity">
@@ -34,6 +36,9 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".HomeActivity"
android:screenOrientation="portrait"/>
<activity
android:name=".ShelfActivity"
android:screenOrientation="portrait"
@@ -1,8 +1,10 @@
package com.shuwei.intelligent.shelves
import android.app.Application
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import com.shuwei.intelligent.shelves.utils.BootReceiver
/**
@@ -10,14 +12,8 @@ import com.shuwei.intelligent.shelves.utils.BootReceiver
* @date: 2022-04-26
*/
class App : Application() {
//从接口获取
var accessToken: String = ""
//"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjYW50ZWVuSWQiOiIiLCJ0eXBlIjoiNiIsInVzZXJJZCI6IjE2NzgyMjY1NTI5MzE1NDkxODYifQ.CQmbELpqT6QzvVCgCeirwvSvPp8Mhft_h6b1Af574Co"
var deviceId:String = ""
var canteenId:String = ""
override fun onCreate() {
super.onCreate()
app = this
@@ -27,9 +23,26 @@ class App : Application() {
companion object {
private lateinit var app: App
var canteenId = "0"
var appVersion = "1"
var configUrl = ""
//从接口获取
var accessToken: String = ""
var deviceId: String = ""
@Volatile
private var sharedPref: SharedPreferences? = null
fun getInstance(): App {
return app
}
fun getSharedPref(): SharedPreferences? {
if (sharedPref != null) {
return sharedPref
}
sharedPref = app.getSharedPreferences("sp_intelligent_shelves", Context.MODE_PRIVATE)
return sharedPref
}
}
}
@@ -133,20 +133,20 @@ class HomeActivity : BaseActivity() {
}
TaskManager.startTask()
var androidId = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
// androidId = "d0e7a2d5f25c775c"
Log.d(TAG, "onCreate: androidId=${androidId}")
if (androidId == "65e1012638f78260" || androidId == "40f89e91ee40611d") {
androidId = "d0e7a2d5f25c775c"
}
App.getInstance().deviceId = androidId
//"53babf69-0d2f-3875-a649-f2e12f80ad4c1"
val swDpValue = resources?.configuration?.smallestScreenWidthDp
Log.d(TAG, "onCreate: swDpValue=$swDpValue")
// var androidId = Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
//// androidId = "d0e7a2d5f25c775c"
// Log.d(TAG, "onCreate: androidId=${androidId}")
// if (androidId == "65e1012638f78260" || androidId == "40f89e91ee40611d") {
// androidId = "d0e7a2d5f25c775c"
// }
// App.deviceId = androidId
// //"53babf69-0d2f-3875-a649-f2e12f80ad4c1"
//
// val swDpValue = resources?.configuration?.smallestScreenWidthDp
// Log.d(TAG, "onCreate: swDpValue=$swDpValue")
viewModel.getAccessToken(App.getInstance().deviceId)
viewModel.getAccessToken(App.deviceId)
// repeat(100) {
// lifecycleScope.launch {
@@ -183,9 +183,9 @@ class HomeActivity : BaseActivity() {
private fun getTokenSuccess(data: RespData<*>) {
Log.d(TAG, "getTokenSuccess: $data")
data.result?.let {
App.getInstance().accessToken = it.toString()
App.accessToken = it.toString()
//UIUtils.toast(it.toString())
viewModel.getShelfList(deviceId = App.getInstance().deviceId)
viewModel.getShelfList(deviceId = App.deviceId)
}
}
@@ -201,7 +201,7 @@ class HomeActivity : BaseActivity() {
loadEmptyView()
return
}
App.getInstance().canteenId = data.result.canteenId
App.canteenId = data.result.canteenId
val tempList = data.result.containerGoodsList
if (tempList.isNullOrEmpty()) {
loadEmptyView()
@@ -215,8 +215,8 @@ class HomeActivity : BaseActivity() {
val subList01 = tempList.subList(0, 5)
val subList02 = tempList.subList(5, 10)
repeat(5) { index ->
list.add(subList01[index].also { it.deviceId = App.getInstance().deviceId })
list.add(subList02[index].also { it.deviceId = App.getInstance().deviceId })
list.add(subList01[index].also { it.deviceId = App.deviceId })
list.add(subList02[index].also { it.deviceId = App.deviceId })
}
shelfAdapter.notifyDataSetChanged()
}
@@ -491,7 +491,7 @@ class HomeActivity : BaseActivity() {
binding.include?.let {
it.root.visible()
it.root.setOnClickListener {
viewModel.getAccessToken(App.getInstance().deviceId)
viewModel.getAccessToken(App.deviceId)
}
it.ivEmptyIcon.setImageResource(R.drawable.ic_empty_white)
it.tvEmptyContent.setTextColor(Color.WHITE)
@@ -0,0 +1,169 @@
package com.shuwei.intelligent.shelves
import android.annotation.SuppressLint
import android.os.Bundle
import android.provider.Settings
import android.util.Log
import androidx.activity.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.shuwei.intelligent.shelves.base.BaseActivity
import com.shuwei.intelligent.shelves.databinding.ActivityInitBinding
import com.shuwei.intelligent.shelves.model.DeviceConfigInfo
import com.shuwei.intelligent.shelves.net.NetViewModel
import com.shuwei.intelligent.shelves.net.UiState
import com.shuwei.intelligent.shelves.net.UrlConfig
import com.shuwei.intelligent.shelves.utils.AppUtil
import com.shuwei.intelligent.shelves.utils.QRCodeUtil
import com.shuwei.intelligent.shelves.utils.SpTool
import com.shuwei.intelligent.shelves.utils.ext.dp
import com.shuwei.intelligent.shelves.utils.ext.invisible
import com.shuwei.intelligent.shelves.utils.ext.startActivity
import com.shuwei.intelligent.shelves.utils.ext.toJsonString
import com.shuwei.intelligent.shelves.utils.ext.toObject
import com.shuwei.intelligent.shelves.utils.ext.toast
import com.shuwei.intelligent.shelves.utils.ext.visible
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch
import kotlin.collections.forEach
import kotlin.getValue
import kotlin.jvm.java
import kotlin.ranges.downTo
import kotlin.text.isBlank
import kotlin.to
class InitActivity : BaseActivity() {
companion object {
const val TAG = "InitActivity"
}
private lateinit var binding: ActivityInitBinding
private val viewModel: NetViewModel by viewModels()
@SuppressLint("HardwareIds")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityInitBinding.inflate(layoutInflater)
setContentView(binding.root)
// 获取 ANDROID_ID
val androidId =
Settings.Secure.getString(contentResolver, Settings.Secure.ANDROID_ID)
App.deviceId = androidId
SpTool.put(SpTool.DEVICE_ID, androidId)
App.configUrl = UrlConfig.BASE_URL
App.canteenId = "0"
// var deviceId = AppUtil.getUDID(this)
// Log.d(TAG, "onCreate: deviceId=$deviceId")
//// deviceId = "39a7abdd06b3c7ab"
//// deviceId = "3ea47dc0-3cf0-3c2f-909c-265a9a65572e"
// App.deviceId = deviceId
//
// SpTool.put(SpTool.DEVICE_ID, deviceId)
// val deviceConfigCache = SpTool.getString(SpTool.DEVICE_CONFIG_CACHE)
// val checkResult = checkConfigData(deviceConfigCache)
// if (checkResult.not()) {
// binding.ivQrCode.visible()
// binding.btnInit.visible()
// //进行初始化操作
// initConfig()
// return
// }
binding.ivQrCode.invisible()
binding.btnInit.invisible()
countDown()
}
private fun countDown() {
lifecycleScope.launch {
flow {
(2 downTo 1).forEach {
delay(1000)
emit(it)
}
}.collect {
// 倒计时结束执行跳转
if (it == 1) {
startActivity<HomeActivity>()
finish()
}
}
}
}
private fun initConfig() {
binding.ivQrCode.setImageBitmap(
QRCodeUtil.generateQRCode(
content = App.deviceId,
size = 200.dp
)
)
binding.btnInit.setOnClickListener {
viewModel.getDeviceToken(App.deviceId)
}
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) {
launch {
viewModel.getDeviceTokenUiState.collect { state ->
when (state) {
is UiState.Loading -> {}
is UiState.Success<*> -> {
state.data.result?.let { deviceToken ->
Log.d(TAG, "initConfig: $deviceToken")
viewModel.getDeviceConfig(
deviceId = App.deviceId,
deviceToken = deviceToken.toString()
)
}
}
is UiState.Error -> toast(state.msg)
else -> {}
}
}
}
launch {
viewModel.getDeviceConfigUiState.collect { state ->
when (state) {
is UiState.Loading -> {}
is UiState.Success<*> -> {
state.data.result?.let {
if (it is DeviceConfigInfo) {
SpTool.put(SpTool.DEVICE_CONFIG_CACHE, it.toJsonString())
App.configUrl = it.appPackageUrl?:""
App.canteenId = it.canteenId?:""
startActivity<HomeActivity>()
finish()
}
}
}
is UiState.Error -> toast(message = state.msg)
else -> {}
}
}
}
}
}
}
private fun checkConfigData(data: String): Boolean {
if (data.isBlank()) {
return false
}
val config = data.toObject<DeviceConfigInfo?>()
if (config == null) {
return false
}
App.configUrl = config.appPackageUrl?:""
App.canteenId = config.canteenId?:""
return true
}
}
@@ -202,7 +202,7 @@ class ShelfActivity : BaseActivity() {
private fun getGoodsList() {
viewModel.getGoodsList(
canteenId = App.getInstance().canteenId,
canteenId = App.canteenId,
goodsName = binding.etInputFood.text.trim().toString(),
pageNo = pageNo,
pageSize = PAGE_SIZE
@@ -0,0 +1,6 @@
package com.shuwei.intelligent.shelves.model
class DeviceConfigInfo {
var appPackageUrl:String? = null
var canteenId:String? = null
}
@@ -1,31 +1,66 @@
package com.shuwei.intelligent.shelves.net
import com.shuwei.intelligent.shelves.App
import com.shuwei.intelligent.shelves.model.DeviceConfigInfo
import com.shuwei.intelligent.shelves.model.GoodsRecord
import com.shuwei.intelligent.shelves.model.ShelfBody
import com.shuwei.intelligent.shelves.model.ShelfResult
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.POST
import retrofit2.http.Query
import retrofit2.http.Url
interface ApiService {
/**
* device获取token
*/
@GET("/sys/getEquipmentToken")
suspend fun getDeviceToken(
@Query("qrcodeId") qrcodeId: String,
@Query("appVersion") appVersion: String = App.appVersion
): RespData<String>
@GET(UrlConfig.GET_ACCESS_TOKEN)
suspend fun getAccessToken(@Query("qrcodeId") qrcodeId: String): RespData<String?>
/**
*获取配置信息
*/
@GET("/equipment/stEquipment/queryByEquipmentCode")
suspend fun getDeviceInfo(
@Query("equipmentCode") equipmentCode: String,
@Query("appVersion") appVersion: String = App.appVersion,
@Header("X-Access-Token") token: String
): RespData<DeviceConfigInfo>
@GET(UrlConfig.GET_SHELF_LIST)
suspend fun getShelfList(@Query("deviceId") deviceId: String): RespData<ShelfResult>
@GET
suspend fun getAccessToken(
@Url url: String = UrlConfig.GET_ACCESS_TOKEN,
@Query("qrcodeId") qrcodeId: String,
@Query("x-access-token") token: String = App.accessToken
): RespData<String?>
@GET(UrlConfig.GET_GOODS_LIST)
@GET
suspend fun getShelfList(
@Url url: String = UrlConfig.GET_SHELF_LIST,
@Query("deviceId") deviceId: String,
@Query("x-access-token") token: String = App.accessToken
): RespData<ShelfResult>
@GET
suspend fun getGoodsList(
@Url url: String = UrlConfig.GET_GOODS_LIST,
@Query("canteenId") canteenId: String = "0",
@Query("goodsName") goodsName: String? = null,
@Query("pageNo") pageNo: Int = 1,
@Query("pageSize") pageSize: Int = 50,
@Query("x-access-token") token: String = App.accessToken
): RespData<GoodsRecord>
@POST(UrlConfig.SAVE_SHELF_GOODS_LIST)
suspend fun saveShelfGoodsList(@Body body: ShelfBody): RespData<Any?>
@POST
suspend fun saveShelfGoodsList(
@Url url: String = UrlConfig.SAVE_SHELF_GOODS_LIST,
@Body body: ShelfBody,
@Query("x-access-token") token: String = App.accessToken
): RespData<Any?>
}
@@ -16,7 +16,8 @@ import java.security.cert.X509Certificate
import kotlin.apply
val apiService: ApiService = Retrofit.Builder()
.baseUrl(UrlConfig.BASE_URL)
// .baseUrl(UrlConfig.BASE_URL)
.baseUrl(UrlConfig.DEVICE_BASE_URL)
.client(HttpManager.instance.client)
.addConverterFactory(GsonConverterFactory.create())
.build()
@@ -32,12 +33,12 @@ class HttpManager private constructor() {
sslSocketFactory(createSSLSocketFactory(), TrustAllCerts())
hostnameVerifier { _, _ -> true }
addInterceptor(LoggingInterceptor())
addInterceptor { chain ->
val request = chain.request().newBuilder()
.header("x-access-token", App.getInstance().accessToken)
.build()
chain.proceed(request)
}
// addInterceptor { chain ->
// val request = chain.request().newBuilder()
// .header("x-access-token", App.accessToken)
// .build()
// chain.proceed(request)
// }
}
.build()
}
@@ -32,11 +32,50 @@ class NetViewModel : ViewModel() {
private val _getAccessTokenUiState = MutableStateFlow<UiState>(UiState.Initial)
val getAccessTokenUiState: StateFlow<UiState> = _getAccessTokenUiState
private val _getDeviceTokenUiState = MutableStateFlow<UiState>(UiState.Initial)
val getDeviceTokenUiState: StateFlow<UiState> = _getDeviceTokenUiState
private val _getDeviceConfigUiState = MutableStateFlow<UiState>(UiState.Initial)
val getDeviceConfigUiState: StateFlow<UiState> = _getDeviceConfigUiState
fun getDeviceToken(deviceId: String) {
viewModelScope.launch {
_getDeviceTokenUiState.value = UiState.Loading
runCatching {
val response = apiService.getDeviceToken(qrcodeId = deviceId)
if (response.success) {
_getDeviceTokenUiState.value = UiState.Success(response)
} else {
_getDeviceTokenUiState.value = UiState.Error(response.message ?: "请求失败")
}
}.onFailure {
_getDeviceTokenUiState.value = UiState.Error(it.message ?: "请求异常")
}
}
}
fun getDeviceConfig(deviceId: String, deviceToken: String) {
viewModelScope.launch {
_getDeviceTokenUiState.value = UiState.Loading
runCatching {
val response = apiService.getDeviceInfo(equipmentCode = deviceId, token = deviceToken)
if (response.success) {
_getDeviceTokenUiState.value = UiState.Success(response)
} else {
_getDeviceTokenUiState.value = UiState.Error(response.message ?: "请求失败")
}
}.onFailure {
_getDeviceTokenUiState.value = UiState.Error(it.message ?: "请求异常")
}
}
}
fun getAccessToken(deviceId: String) {
viewModelScope.launch {
_getAccessTokenUiState.value = UiState.Loading
runCatching {
val response = apiService.getAccessToken(deviceId)
val response = apiService.getAccessToken(qrcodeId = deviceId)
if (response.success) {
_getAccessTokenUiState.value = UiState.Success(response)
} else {
@@ -52,7 +91,7 @@ class NetViewModel : ViewModel() {
viewModelScope.launch {
_getShelfListUiState.value = UiState.Loading
runCatching {
val response = apiService.getShelfList(deviceId)
val response = apiService.getShelfList(deviceId = deviceId)
if (response.success) {
_getShelfListUiState.value = UiState.Success(response)
} else {
@@ -1,13 +1,24 @@
package com.shuwei.intelligent.shelves.net
import com.shuwei.intelligent.shelves.App
object UrlConfig {
const val DEVICE_BASE_URL = "http://device.shuziweidao.com:8889"
// /**
// * device获取token
// */
// const val DEVICE_TOKEN = "${DEVICE_BASE_URL}/sys/getEquipmentToken"
// /**
// *获取配置信息
// */
// const val DEVICE_CONFIG = "${DEVICE_BASE_URL}/equipment/stEquipment/queryByEquipmentCode"
// const val BASE_URL = "http://192.168.1.3:9002"
const val BASE_URL = "https://yyjk.shuziweidao.com/gateway/"
const val GET_ACCESS_TOKEN = "restaurant/equipment/stEquipment/getEquipmentToken"
const val GET_SHELF_LIST = "inventory/smartShelves/app/getShelvesListByDeviceId"
const val GET_GOODS_LIST = "inventory/smartShelves/app/getGoodsPageList"
const val SAVE_SHELF_GOODS_LIST = "inventory/smartShelves/app/saveShelvesGoodsList"
const val BASE_URL = "https://yyjk.shuziweidao.com/gateway"
var GET_ACCESS_TOKEN = "${App.configUrl}/restaurant/equipment/stEquipment/getEquipmentToken"
var GET_SHELF_LIST = "${App.configUrl}/inventory/smartShelves/app/getShelvesListByDeviceId"
var GET_GOODS_LIST = "${App.configUrl}/inventory/smartShelves/app/getGoodsPageList"
var SAVE_SHELF_GOODS_LIST = "${App.configUrl}/inventory/smartShelves/app/saveShelvesGoodsList"
}
@@ -43,13 +43,13 @@ class SyncTask(appContext: Context, workerParams: WorkerParameters) :
it.humidity = HomeActivity.showHumidity
}
val body = ShelfBody().also {
it.deviceId = App.getInstance().deviceId
it.canteenId = App.getInstance().canteenId
it.deviceId = App.deviceId ?: ""
it.canteenId = App.canteenId
it.temperature = HomeActivity.showTemperatureC
it.humidity = HomeActivity.showHumidity
it.goodsList = submitList
}
val resp = apiService.saveShelfGoodsList(body)
val resp = apiService.saveShelfGoodsList(body = body)
Log.d(TAG, "performSync: body:${body.toJsonString()}")
Log.d(TAG, "performSync: resp:${resp.toJsonString()}")
}
@@ -0,0 +1,751 @@
package com.shuwei.intelligent.shelves.utils;
import static android.content.Context.TELEPHONY_SERVICE;
import android.annotation.SuppressLint;
import android.bluetooth.BluetoothAdapter;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
import androidx.core.content.FileProvider;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.NetworkInterface;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
public class AppUtil {
public static String getAppPackageName(Context context) {
String packageName = "";
try {
PackageManager pm = context.getPackageManager();
PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
packageName = pi.packageName;
if (AppUtil.isEmpty(packageName)) {
return "";
}
} catch (Exception e) {
e.printStackTrace();
}
return packageName;
}
public static String getAppVersionName(Context context) {
String versionName = "";
// int versioncode=1;
try {
PackageManager pm = context.getPackageManager();
PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
versionName = pi.versionName;
// versioncode = pi.versionCode;表示更新了多少次
if (versionName == null || versionName.length() <= 0) {
return "";
}
} catch (Exception e) {
e.printStackTrace();
}
return versionName;
}
public static int getAppVersionCode(Context context) {
int versioncode = 1;
try {
PackageManager pm = context.getPackageManager();
PackageInfo pi = pm.getPackageInfo(context.getPackageName(), 0);
versioncode = pi.versionCode;
} catch (Exception e) {
e.printStackTrace();
}
return versioncode;
}
//判断微信是否安装
public static boolean isWeixinInstalled(Context context) {
final PackageManager packageManager = context.getPackageManager();// 获取packagemanager
List<PackageInfo> pinfo = packageManager.getInstalledPackages(0);// 获取所有已安装程序的包信息
if (pinfo != null) {
for (int i = 0; i < pinfo.size(); i++) {
String pn = pinfo.get(i).packageName;
if (pn.equals("com.tencent.mm")) {
return true;
}
}
}
return false;
}
/**
* 打电话
* <p>
* Intent.ACTION_DIAL Intent.ACTION_CALL
*
* @param context
* @param mobile
*/
public static void callUp(Context context, String mobile) {
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:"
+ mobile));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
/**
* 获取设备ID
*
* @param context
* @return
*/
public static String getDevId(Context context) {
TelephonyManager TelephonyMgr = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
return TelephonyMgr.getDeviceId();
}
/**
* 姓名脱敏
*
* @param fullName
* @return
*/
public static String desensitizedName(String fullName) {
if (fullName == null || fullName.length() <= 1) {
return fullName;
}
char[] nameArr = fullName.toCharArray();
if (nameArr.length > 2) {
for (int i = 1; i < nameArr.length - 1; i++) {
nameArr[i] = '*';
}
} else {
nameArr[1] = '*';
}
return new String(nameArr);
}
public static String formatDateGetFull(String date) {
if (isEmpty(date)) {
return "";
}
Date d = new Date(Long.parseLong(date));
SimpleDateFormat dateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm");
return dateFormat1.format(d);
}
public static String formatDateGetCurrentTime() {
Date d = new Date(System.currentTimeMillis());
SimpleDateFormat dateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//.SSS
return dateFormat1.format(d);
}
public static String formatDateGetFull(long date) {
if (date == 0) {
return "";
}
Date d = new Date(date);
SimpleDateFormat dateFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
return dateFormat1.format(d);
}
public static String formatDateGetDay(long date) {
if (date == 0) {
return "";
}
Date d = new Date(date);
SimpleDateFormat dateFormat1 = new SimpleDateFormat("yyyy-MM-dd");
return dateFormat1.format(d);
}
public static boolean isEmpty(String s) {
if (TextUtils.isEmpty(s) || s.trim().equals("null")) {
return true;
} else {
return false;
}
}
/**
* 格式化浮点型
*
* @param data
* @return
*/
public static String formatDouble(double data) {
return new DecimalFormat("0.00").format(data);
}
/**
* 格式化分钟
*
* @param minutes
* @return
*/
public static String formatMinutes(int minutes) {
int hour = minutes / 60;
int minute = minutes % 60;
if (hour > 0 && minute > 0) {
return hour + "小时" + minute + "分钟";
} else if (hour > 0) {
return hour + "小时";
} else {
return minute + "分钟";
}
}
//com.fawan.news
public static void goToMarket(Context context, String packageName) {
Uri uri = Uri.parse("market://details?id=" + packageName);
Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
try {
context.startActivity(goToMarket);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
}
}
/**
* true为存在,false为不存在
*
* @param context
* @param packageName
* @return
*/
public static boolean isInstallApp(Context context, String packageName) {
try {
context.getPackageManager().getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
/**
* 格式化float 保留两位小数
*
* @param data
* @return
*/
public static float formatFloat2(float data) {
// DecimalFormat decimalFormat = new DecimalFormat("0.00");//构造方法的字符格式这里如果小数不足2位,会以0补足.
// return decimalFormat.format(data);//返回字符串
int scale = 1;//设置位数
int roundingMode = 4;//表示四舍五入,可以选择其他舍值方式,例如去尾,等等.
BigDecimal bd = new BigDecimal((double) data);
bd = bd.setScale(scale, roundingMode);
data = bd.floatValue();
return data;
}
/**
* Android 6.0 之前(不包括6.0)获取mac地址
* 必须的权限 <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
*
* @param context * @return
*/
public static String getMacDefault(Context context) {
String mac = "";
if (context == null) {
return mac;
}
WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
WifiInfo info = null;
try {
info = wifi.getConnectionInfo();
} catch (Exception e) {
e.printStackTrace();
}
if (info == null) {
return null;
}
mac = info.getMacAddress();
if (!TextUtils.isEmpty(mac)) {
mac = mac.toUpperCase(Locale.ENGLISH);
}
return mac;
}
/**
* Android 6.0-Android 7.0 获取mac地址
*/
public static String getMacAddress() {
String macSerial = null;
String str = "";
try {
Process pp = Runtime.getRuntime().exec("cat/sys/class/net/wlan0/address");
InputStreamReader ir = new InputStreamReader(pp.getInputStream());
LineNumberReader input = new LineNumberReader(ir);
while (null != str) {
str = input.readLine();
if (str != null) {
macSerial = str.trim();//去空格
break;
}
}
} catch (IOException ex) {
// 赋予默认值
ex.printStackTrace();
}
return macSerial;
}
/**
* Android 7.0之后获取Mac地址
* 遍历循环所有的网络接口,找到接口是 wlan0
* 必须的权限 <uses-permission android:name="android.permission.INTERNET"></uses-permission>
*
* @return
*/
public static String getMacFromHardware() {
try {
ArrayList<NetworkInterface> all = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface nif : all) {
if (!nif.getName().equals("wlan0"))
continue;
byte[] macBytes = nif.getHardwareAddress();
if (macBytes == null) return "";
StringBuilder res1 = new StringBuilder();
for (Byte b : macBytes) {
res1.append(String.format("%02X:", b));
}
if (!TextUtils.isEmpty(res1)) {
res1.deleteCharAt(res1.length() - 1);
}
return res1.toString();
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
/**
* 获取mac地址(适配所有Android版本)
*
* @return
*/
public static String getMac(Context context) {
String mac = "";
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
mac = getMacDefault(context);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
mac = getMacAddress();
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mac = getMacFromHardware();
}
return mac;
}
//把String转化为float
public static double convertToFloat(String number, double defaultValue) {
if (TextUtils.isEmpty(number)) {
return defaultValue;
}
try {
return Double.parseDouble(number);
} catch (Exception e) {
return defaultValue;
}
}
/**
* 获取AndroidId
*
* @param context
* @return
*/
public static String getAndroidId(Context context) {
String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
return androidId;
}
/**
* 获取设备唯一 UDID
*
* @param context
* @return
*/
@SuppressLint("MissingPermission")
public static String getUDID(Context context) {
// String androidID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
// L.e("androidID===" + androidID);
// return androidID;
String androidID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
if (!androidID.equals("")) {
try {
if (!"9774d56d682e549c".equals(androidID)) {
androidID = UUID.nameUUIDFromBytes(androidID.getBytes("utf8")).toString();
} else {
@SuppressLint("MissingPermission") final String deviceId = ((TelephonyManager) context.getSystemService(TELEPHONY_SERVICE)).getDeviceId();
androidID = deviceId != null ? UUID.nameUUIDFromBytes(deviceId.getBytes("utf8")).toString() : UUID.randomUUID().toString();
}
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
return androidID;
}
//需要权限 android.permission.READ_PHONE_STATE
TelephonyManager TelephonyMgr = (TelephonyManager) context.getSystemService(TELEPHONY_SERVICE);
String szImei = TelephonyMgr.getDeviceId();
if (!szImei.equals("")) {
return szImei;
}
//需要权限 android.permission.ACCESS_WIFI_STATE
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
String m_szWLANMAC = wm.getConnectionInfo().getMacAddress();
if (!m_szWLANMAC.equals("")) {
return m_szWLANMAC;
}
//需要权限 android.permission.BLUETOOTH
BluetoothAdapter m_BluetoothAdapter = null;
m_BluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
String m_szBTMAC = m_BluetoothAdapter.getAddress();
if (!m_szBTMAC.equals("")) {
return m_szBTMAC;
}
return getUniquePsuedoID();
}
//获得 Psuedo ID
public static String getUniquePsuedoID() {
String serial = null;
String m_szDevIDShort = "35" +
Build.BOARD.length() % 10 + Build.BRAND.length() % 10 +
Build.CPU_ABI.length() % 10 + Build.DEVICE.length() % 10 +
Build.DISPLAY.length() % 10 + Build.HOST.length() % 10 +
Build.ID.length() % 10 + Build.MANUFACTURER.length() % 10 +
Build.MODEL.length() % 10 + Build.PRODUCT.length() % 10 +
Build.TAGS.length() % 10 + Build.TYPE.length() % 10 +
Build.USER.length() % 10; //13 位
try {
serial = Build.class.getField("SERIAL").get(null).toString();
//API>=9 使用serial号
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
} catch (Exception exception) {
//serial需要一个初始化,随意值
serial = "serial";
}
//使用硬件信息拼凑出来的15位号码
return new UUID(m_szDevIDShort.hashCode(), serial.hashCode()).toString();
}
public static String getCPUSerial() {
String line = "";
String TAG = "aaa";
Log.e(TAG, " get_quck_Sn() ");
Class<?> c = null;
try {
c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class);
line = (String) get.invoke(c, "ro.serialno");
} catch (ClassNotFoundException | NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Log.e(TAG, " get_quck_Sn() " + line);
System.out.println("设备串号" + line);
return line;
}
/**
* 判断网络连接状态
*
* @param context
* @return
*/
public static boolean isNetworkConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
if (mNetworkInfo != null) {
return mNetworkInfo.isAvailable();
}
}
return false;
}
/**
* 判断WiFi连接状态
*
* @param context
* @return
*/
public static boolean isWifiConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWiFiNetworkInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
if (mWiFiNetworkInfo != null) {
return mWiFiNetworkInfo.isAvailable();
}
}
return false;
}
/**
* 判断移动网络状态
*
* @param context
* @return
*/
public static boolean isMobileConnected(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mMobileNetworkInfo = mConnectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
if (mMobileNetworkInfo != null) {
return mMobileNetworkInfo.isAvailable();
}
}
return false;
}
/**
* 获取网络连接类型
*
* @param context
* @return
*/
public static int getConnectedType(Context context) {
if (context != null) {
ConnectivityManager mConnectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mNetworkInfo = mConnectivityManager.getActiveNetworkInfo();
if (mNetworkInfo != null && mNetworkInfo.isAvailable()) {
return mNetworkInfo.getType();
}
}
return -1;
}
/**
* 根据字符的起始和结束索引提取子串
*
* @param input 原始字符串
* @param startIndex 起始索引(包含,从0开始)
* @param endIndex 结束索引(不包含)
* @return 子串,若输入无效或索引越界则返回空字符串
*/
public static String getSubstringByIndices(String input, int startIndex, int endIndex) {
if (input == null) {
return "";
}
// 处理索引越界问题
int safeStart = Math.max(startIndex, 0);
int safeEnd = Math.min(endIndex, input.length());
if (safeStart > safeEnd) {
return "";
}
return input.substring(safeStart, safeEnd);
}
public static String getSubstringByIndex(String input, int startIndex, int length) {
if (input == null) {
return "";
}
// 处理索引越界问题
int safeStart = Math.max(startIndex, 0);
int safeEnd = Math.min(startIndex + length, input.length());
if (safeStart > safeEnd) {
return "";
}
return input.substring(safeStart, safeEnd);
}
/**
* 十进制转十六进制
*
* @param decimal
* @return
*/
public static String decimalToHexWithPadding(int decimal, int padding) {
// 将十进制转换为十六进制,并转换为字符串
String hex = Integer.toHexString(decimal);
// 确保字符串长度为至少4位,不足部分前面补0
while (hex.length() < padding) {
hex = "0" + hex;
}
return hex.toUpperCase(); // 返回大写形式的十六进制字符串
}
/**
* 十进制转二进制,且返回的二进制为至少7位数
*
* @param decimal
* @return
*/
public static String decimalToBinary(int decimal) {
// 如果输入为0,直接返回"0"
if (decimal == 0) {
return "0";
}
StringBuilder binary = new StringBuilder();
// 除2取余法,将余数加入二进制字符串
while (decimal > 0) {
int remainder = decimal % 2;
binary.insert(0, remainder);
decimal = decimal / 2;
}
int length = binary.length();
if (length < 7) {
int padding = 7 - length;
for (int i = 0; i < padding; i++) {
binary.insert(0, '0');
}
}
return binary.toString();
}
/**
* 将二进制字符串转换为十六进制字符串,每8位转换为两位十六进制,不足两位前面补零
*
* @param binaryStr 输入的二进制字符串(仅包含0和1)
* @return 转换后的十六进制字符串
* @throws IllegalArgumentException 如果输入不是有效的二进制字符串
*/
public static String binaryToHex(String binaryStr) {
// 校验输入合法性
if (binaryStr == null || !binaryStr.matches("[01]+")) {
throw new IllegalArgumentException("Invalid binary string");
}
// 补前导零使长度成为8的倍数
int length = binaryStr.length();
int padding = (8 - (length % 8)) % 8; // 计算需要补零的数量
StringBuilder paddedBinary = new StringBuilder();
for (int i = 0; i < padding; i++) {
paddedBinary.append('0');
}
paddedBinary.append(binaryStr);
// 每8位转换为两位十六进制
StringBuilder hexStr = new StringBuilder();
for (int i = 0; i < paddedBinary.length(); i += 8) {
String byteStr = paddedBinary.substring(i, i + 8);
int decimalValue = Integer.parseInt(byteStr, 2);
hexStr.append(String.format("%02X", decimalValue & 0xFF));
}
return hexStr.toString();
}
/**
* 数据校验 异或处理
*/
public static String getXor(String content) {
int a = 0;
for (int i = 0; i < content.length() / 2; i++) {
a = a ^ Integer.parseInt(content.substring(i * 2, (i * 2) + 2), 16);
}
String result = Integer.toHexString(a).toUpperCase();
if (result.length() == 1) {
return "0" + result;
} else {
return result;
}
}
public static double formatPersonInfo(String input, int startIndex, int length) {
if (input == null) {
return 0;
}
// 处理索引越界问题
int safeStart = Math.max(startIndex, 0);
int safeEnd = Math.min(startIndex + length, input.length());
if (safeStart > safeEnd) {
return 0;
}
String result = input.substring(safeStart, safeEnd);
double num = Integer.parseInt(result, 16);
return num;
}
/**
* 安装apk
*
* @param activity
* @param apkFile
*/
public static void installApk(Context activity, File apkFile) {
//文件有所有者概念,现在是属于当前进程的,需要把这个文件暴露给系统安装程序(其他进程)去安装
//因此,可能会存在权限问题,需要做下面的设置
//如果文件是sdcard上的,就不需要这个操作了
try {
apkFile.setExecutable(true, false);
apkFile.setReadable(true, false);
apkFile.setWritable(true, false);
} catch (Exception e) {
e.printStackTrace();
}
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(Intent.ACTION_VIEW);
Uri uri;
//TODO N FileProvider
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
uri = FileProvider.getUriForFile(activity, activity.getPackageName() + ".fileProvider", apkFile);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
} else {
uri = Uri.fromFile(apkFile);
}
intent.setDataAndType(uri, "application/vnd.android.package-archive");
activity.startActivity(intent);
//TODO 0 INSTALL PERMISSION
//在AndroidManifest中加入权限即可
}
}
@@ -0,0 +1,101 @@
package com.shuwei.intelligent.shelves.utils
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.WriterException
import com.google.zxing.common.BitMatrix
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
/**
* 二维码生成工具类
*/
object QRCodeUtil {
/**
* 生成二维码(默认大小)
* @param content 二维码内容
* @return 生成的二维码Bitmap
*/
@JvmOverloads
fun generateQRCode(content: String, size: Int = 500): Bitmap? {
return generateQRCode(content, size, Color.BLACK, Color.WHITE)
}
/**
* 生成二维码(自定义颜色)
* @param content 二维码内容
* @param size 二维码边长(像素)
* @param colorCode 二维码颜色
* @param backgroundColor 背景颜色
* @return 生成的二维码Bitmap
*/
fun generateQRCode(
content: String,
size: Int,
colorCode: Int,
backgroundColor: Int
): Bitmap? {
if (content.isEmpty()) {
return null
}
return try {
val hints = mutableMapOf<EncodeHintType, Any>().apply {
put(EncodeHintType.CHARACTER_SET, "UTF-8")
put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H) // 纠错级别
put(EncodeHintType.MARGIN, 1) // 边距
}
val bitMatrix = QRCodeWriter().encode(
content,
BarcodeFormat.QR_CODE,
size,
size,
hints
)
val pixels = IntArray(size * size).apply {
for (y in 0 until size) {
for (x in 0 until size) {
this[y * size + x] = if (bitMatrix.get(x, y)) colorCode else backgroundColor
}
}
}
Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888).apply {
setPixels(pixels, 0, size, 0, 0, size, size)
}
} catch (e: WriterException) {
e.printStackTrace()
null
}
}
/**
* 生成带Logo的二维码
* @param content 二维码内容
* @param size 二维码边长(像素)
* @param logo Logo Bitmap
* @return 带Logo的二维码Bitmap
*/
fun generateQRCodeWithLogo(content: String, size: Int, logo: Bitmap?): Bitmap? {
val qrCode = generateQRCode(content, size) ?: return null
logo ?: return qrCode
val logoSize = size / 5 // Logo大小约为二维码的1/5
val scaledLogo = Bitmap.createScaledBitmap(logo, logoSize, logoSize, false)
val offset = (size - logoSize) / 2
return Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888).apply {
val canvas = Canvas(this)
canvas.drawBitmap(qrCode, 0f, 0f, null)
canvas.drawBitmap(scaledLogo, offset.toFloat(), offset.toFloat(), null)
}
}
}
@@ -0,0 +1,31 @@
package com.shuwei.intelligent.shelves.utils
import com.shuwei.intelligent.shelves.App
import com.shuwei.intelligent.shelves.utils.ext.put
import kotlin.to
object SpTool {
const val DEVICE_CONFIG_CACHE = "deviceConfigCache"
const val TOKEN = "token"
const val LAUNCH_PAGE_TYPE = "launchPageType"
const val DEVICE_ID = "deviceId"
val pref = App.getSharedPref()!!
fun put(key: String, value: Any) {
pref.put(key to value)
}
fun getInt(key: String, defValue: Int = 0): Int {
return pref.getInt(key, defValue)
}
fun getString(key: String, defValue: String? = ""): String {
return pref.getString(key, defValue) ?: ""
}
fun getBoolean(key: String, defValue: Boolean = false): Boolean {
return pref.getBoolean(key, defValue)
}
}
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="#30000000">
<item>
<shape android:shape="rectangle">
<solid android:color="#ff08C6DC" />
<corners android:radius="8dp" />
</shape>
</item>
</ripple>
Binary file not shown.

After

Width:  |  Height:  |  Size: 999 KiB

+49
View File
@@ -0,0 +1,49 @@
<?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="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="450dp"
android:layout_height="450dp"
android:layout_gravity="center_horizontal"
android:layout_marginStart="50dp"
android:layout_marginTop="150dp"
android:layout_marginEnd="50dp"
android:src="@drawable/img_init"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/btnInit"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="100dp"
android:background="@drawable/bg_init_button"
android:gravity="center"
android:padding="10dp"
android:text="设备初始化"
android:textColor="@color/white"
android:textSize="30sp"
android:textStyle="bold"
android:visibility="visible"
tools:ignore="HardcodedText" />
<Space
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1" />
<ImageView
android:id="@+id/ivQrCode"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="50dp"
tools:ignore="ContentDescription"
tools:src="@mipmap/ic_logo512" />
</LinearLayout>
Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">192.168.1.3</domain>
<domain includeSubdomains="true">192.168.1.7</domain>
</domain-config>
<!-- <domain-config cleartextTrafficPermitted="true">-->
<!-- <domain includeSubdomains="true">192.168.1.3</domain>-->
<!-- <domain includeSubdomains="true">192.168.1.7</domain>-->
<!-- </domain-config> -->
<base-config cleartextTrafficPermitted="true" />
</network-security-config>
+4
View File
@@ -8,8 +8,12 @@ junitVersion = "1.1.5"
espressoCore = "3.5.1"
appcompat = "1.6.1"
material = "1.10.0"
core = "3.4.1"
androidCore = "3.3.0"
[libraries]
android-core = { module = "com.google.zxing:android-core", version.ref = "androidCore" }
core = { module = "com.google.zxing:core", version.ref = "core" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }