Commit 2649c8d5 authored by wanglei's avatar wanglei

...

parent bdc8002b
...@@ -48,5 +48,15 @@ dependencies { ...@@ -48,5 +48,15 @@ dependencies {
androidTestImplementation(libs.androidx.espresso.core) androidTestImplementation(libs.androidx.espresso.core)
//第三方UI //第三方UI
implementation("com.airbnb.android:lottie:6.4.0")
implementation("com.github.angcyo.DslTablayout:TabLayout:3.5.5") implementation("com.github.angcyo.DslTablayout:TabLayout:3.5.5")
//相机
val cameraxVersion = "1.2.2"
implementation("androidx.camera:camera-core:${cameraxVersion}")
implementation("androidx.camera:camera-camera2:${cameraxVersion}")
implementation("androidx.camera:camera-view:${cameraxVersion}")
implementation("androidx.camera:camera-lifecycle:${cameraxVersion}")
} }
\ No newline at end of file
...@@ -2,7 +2,15 @@ ...@@ -2,7 +2,15 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"> xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/> <!--required设置为true,无相机设备google play上不会分发-->
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
......
{"v":"5.5.7","fr":60,"ip":0,"op":60,"w":640,"h":140,"nm":"合成 1","ddd":0,"assets":[{"id":"image_0","w":157,"h":175,"u":"images/","p":"img_0.png","e":0},{"id":"image_1","w":86,"h":50,"u":"images/","p":"img_1.png","e":0},{"id":"image_2","w":540,"h":114,"u":"images/","p":"img_2.png","e":0}],"layers":[{"ddd":0,"ind":1,"ty":2,"nm":"bu.png","cl":"png","refId":"image_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[518,94.5,0],"to":[5.917,0,0],"ti":[-5.917,0,0]},{"t":30,"s":[553.5,94.5,0]}],"ix":2},"a":{"a":0,"k":[78.5,87.5,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":2,"nm":"on.png","cl":"png","refId":"image_1","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":22,"s":[0]},{"t":31,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[502.25,57.5,0],"ix":2},"a":{"a":0,"k":[43,25,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":60,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":2,"nm":"qx2.png","cl":"png","refId":"image_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[320,57,0],"ix":2},"a":{"a":0,"k":[270,57,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":60,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
package com.base.browserwhite.ui.activity.scanqrc package com.base.browserwhite.ui.activity.scanqrc
import android.Manifest
import android.graphics.Color
import androidx.camera.core.AspectRatio
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.content.ContextCompat
import androidx.core.view.updatePadding
import com.base.browserwhite.databinding.ActivityScanQrcBinding import com.base.browserwhite.databinding.ActivityScanQrcBinding
import com.base.browserwhite.ui.activity.BaseActivity import com.base.browserwhite.ui.activity.BaseActivity
import com.base.browserwhite.ui.views.DialogViews.showGerPermission
import com.base.browserwhite.utils.BarUtils
import com.base.browserwhite.utils.PermissionHelp.checkCameraPermission
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
class ScanQRCActivity : BaseActivity<ActivityScanQrcBinding>() { class ScanQRCActivity : BaseActivity<ActivityScanQrcBinding>() {
...@@ -9,7 +26,117 @@ class ScanQRCActivity : BaseActivity<ActivityScanQrcBinding>() { ...@@ -9,7 +26,117 @@ class ScanQRCActivity : BaseActivity<ActivityScanQrcBinding>() {
ActivityScanQrcBinding.inflate(layoutInflater) ActivityScanQrcBinding.inflate(layoutInflater)
} }
//相机
private var camera: Camera? = null
private var preview: Preview? = null
private var lensFacing: Int = CameraSelector.LENS_FACING_BACK
private var cameraProvider: ProcessCameraProvider? = null
private lateinit var cameraExecutor: ExecutorService
override fun initView() { override fun initView() {
BarUtils.setStatusBarLightMode(this, true)
BarUtils.setStatusBarColor(this, Color.TRANSPARENT)
binding.root.updatePadding(top = BarUtils.getStatusBarHeight())
if (checkCameraPermission()) {
initCamera()
} else {
showGerPermission(desc = "") {
launcher.launch(arrayOf(Manifest.permission.CAMERA)) { map ->
if (map.values.all { it }) {
initCamera()
} else {
finishToMain()
}
}
} }
}
}
private fun initCamera() {
cameraExecutor = Executors.newSingleThreadExecutor()
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
//初始化相机
cameraProvider = cameraProviderFuture.get()
bindCameraUseCases(lensFacing)
}, ContextCompat.getMainExecutor(this))
}
//绑定设置和相机实例
private fun bindCameraUseCases(lensFacing: Int) {
val aspectRation = aspectRatio(
binding.previewView.width,
binding.previewView.height
)
val rotation = binding.previewView.display.rotation
// 选择相机
val cameraSelector = CameraSelector.Builder().requireLensFacing(lensFacing).build()
//构建预览
preview = buildPreview(aspectRation, rotation)
//构建图片捕捉类
// imageCapture = buildImageCapture(aspectRation, rotation)
//构建图片分析器
// imageAnalyzer = buildImageAnalysis(aspectRation, rotation) {
// it.setAnalyzer(cameraExecutor, LuminosityAnalyzer())
// }
//每次绑定需先解绑
cameraProvider?.unbindAll()
try {
camera = cameraProvider?.bindToLifecycle(
this, cameraSelector, preview
)
preview?.setSurfaceProvider(binding.previewView.surfaceProvider)
} catch (exc: Exception) {
exc.printStackTrace()
}
}
/**
* 构建横纵比
*/
private fun aspectRatio(width: Int, height: Int): Int {
val previewRatio = max(width, height).toDouble() / min(width, height)
if (abs(previewRatio - RATIO_4_3_VALUE) <= abs(previewRatio - RATIO_16_9_VALUE)) {
return AspectRatio.RATIO_4_3
}
return AspectRatio.RATIO_16_9
}
/**
* 构建预览图
* @param aspectRatio 宽高比
* @param rotation 预览图方向
*/
private fun buildPreview(aspectRatio: Int, rotation: Int): Preview {
return Preview.Builder()
.setTargetAspectRatio(aspectRatio)
.setTargetRotation(rotation)
.build()
}
override fun onDestroy() {
super.onDestroy()
cameraExecutor.shutdown()
}
companion object {
//横纵比
private const val RATIO_4_3_VALUE = 4.0 / 3.0
private const val RATIO_16_9_VALUE = 16.0 / 9.0
}
} }
\ No newline at end of file
package com.base.browserwhite.ui.views package com.base.browserwhite.ui.views
import android.annotation.SuppressLint
import android.app.AlertDialog import android.app.AlertDialog
import android.app.Dialog
import android.content.Context import android.content.Context
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.widget.FrameLayout import android.widget.FrameLayout
...@@ -13,12 +17,52 @@ import com.base.browserwhite.bean.ConstObject.GOOGLE ...@@ -13,12 +17,52 @@ import com.base.browserwhite.bean.ConstObject.GOOGLE
import com.base.browserwhite.bean.ConstObject.YAHOO import com.base.browserwhite.bean.ConstObject.YAHOO
import com.base.browserwhite.bean.ConstObject.YANDEX import com.base.browserwhite.bean.ConstObject.YANDEX
import com.base.browserwhite.databinding.DialogMyAccountBinding import com.base.browserwhite.databinding.DialogMyAccountBinding
import com.base.browserwhite.databinding.DialogPermissonOpenBinding
import com.base.browserwhite.databinding.DialogSearchEngineBinding import com.base.browserwhite.databinding.DialogSearchEngineBinding
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog import com.google.android.material.bottomsheet.BottomSheetDialog
object DialogViews { object DialogViews {
@SuppressLint("SetTextI18n")
fun Context.showGerPermission(
tittle: String? = null,
desc: String? = null,
denyText: String? = null,
allowText: String? = null,
deny: ((view: Dialog) -> Unit)? = null,
allow: ((view: Dialog) -> Unit)? = null
): Dialog {
val dialog = Dialog(this)
val binding = DialogPermissonOpenBinding.inflate(LayoutInflater.from(this))
dialog.requestWindowFeature(1)
dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
dialog.window!!.setLayout(-1, -1)
dialog.setCanceledOnTouchOutside(false)
dialog.setCancelable(false)
dialog.setContentView(binding.root)
val str = resources.getString(R.string.app_name)
tittle?.let { binding.tvTitle.text = it }
desc?.let { binding.tvDesc.text = it }
denyText?.let { binding.idDeny.text = it }
allowText?.let { binding.idTvAllow.text = it }
binding.idFullLottie.imageAssetsFolder = "permission_finger/images/"
binding.idFullLottie.setAnimation("permission_finger/data.json")
binding.idFullLottie.playAnimation()
binding.idDeny.setOnClickListener {
dialog.dismiss()
deny?.invoke(dialog)
}
binding.idTvAllow.setOnClickListener {
dialog.dismiss()
allow?.invoke(dialog)
}
dialog.show()
return dialog
}
fun Context.showSearchEngineDialog(selectWebSite: String = GOOGLE, confirmAction: (webSite: String) -> Unit) { fun Context.showSearchEngineDialog(selectWebSite: String = GOOGLE, confirmAction: (webSite: String) -> Unit) {
val binding = DialogSearchEngineBinding.inflate(LayoutInflater.from(this)) val binding = DialogSearchEngineBinding.inflate(LayoutInflater.from(this))
......
package com.base.browserwhite.ui.views
import android.content.Context
import android.graphics.Canvas
import android.util.AttributeSet
import com.airbnb.lottie.LottieAnimationView
class XmlLottieAnimationView : LottieAnimationView {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun draw(canvas: Canvas) {
try {
super.draw(canvas)
} catch (e: Exception) {
}
}
override fun playAnimation() {
super.playAnimation()
}
}
\ No newline at end of file
package com.base.browserwhite.utils
import android.Manifest
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import androidx.core.app.ActivityCompat
import com.base.browserwhite.utils.PermissionHelp.checkStorePermission
object PermissionHelp {
fun Context.checkCameraPermission(): Boolean {
return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
}
fun Context.checkStorePermission(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
Environment.isExternalStorageManager()
} else {
val readPermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
val writePermission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
return readPermission == PackageManager.PERMISSION_GRANTED && writePermission == PackageManager.PERMISSION_GRANTED;
}
}
fun Context.requestStorePermission(
launcher: ActivityLauncher,
jumpAction: (() -> Unit)? = null,
result: (flag: Boolean) -> Unit
) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val intent =
Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
intent.addCategory("android.intent.category.DEFAULT")
intent.data = Uri.parse("package:${packageName}")
jumpAction?.invoke()
launcher.launch(intent) {
result.invoke(checkStorePermission())
}
} else {
launcher.launch(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { map ->
result(map.values.all { it })
}
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="18dp" />
<solid android:color="#355BEA" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#F5F5F5" />
<corners android:radius="18dp" />
</shape>
\ No newline at end of file
...@@ -7,4 +7,9 @@ ...@@ -7,4 +7,9 @@
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".ui.activity.scanqrc.ScanQRCActivity"> tools:context=".ui.activity.scanqrc.ScanQRCActivity">
<androidx.camera.view.PreviewView
android:id="@+id/previewView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat 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:layout_gravity="center"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="12dp"
android:background="@drawable/bg_ffffff_10"
android:orientation="vertical">
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="24dp"
android:text="Permission request"
android:textColor="#000000"
android:textSize="17sp"
android:textStyle="bold"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/tv_desc"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="22dp"
android:layout_marginBottom="38dp"
android:textSize="13sp" />
<com.airbnb.lottie.LottieAnimationView
android:id="@+id/id_full_lottie"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
app:lottie_autoPlay="true"
app:lottie_loop="true" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="23dp"
android:layout_marginTop="40dp"
android:layout_marginBottom="14dp">
<TextView
android:id="@+id/id_deny"
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_marginEnd="13dp"
android:layout_weight="1"
android:background="@drawable/bg_f5f5f5_18"
android:gravity="center"
android:text="Deny"
android:textColor="#000000"
android:textSize="17sp"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/id_tv_allow"
android:layout_width="0dp"
android:layout_height="36dp"
android:layout_weight="1"
android:background="@drawable/bg_355bea_18"
android:gravity="center"
android:text="Allow"
android:textColor="@color/white"
android:textSize="17sp"
tools:ignore="HardcodedText" />
</androidx.appcompat.widget.LinearLayoutCompat>
</LinearLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment