Browse Source

@fun: adm-base

bai 3 years ago
parent
commit
5dc0c904fa

+ 1 - 0
adm-base/.gitignore

@@ -0,0 +1 @@
+/build

+ 47 - 0
adm-base/build.gradle.kts

@@ -0,0 +1,47 @@
+plugins {
+    id("com.android.library")
+    id("org.jetbrains.kotlin.android")
+}
+
+android {
+    compileSdk = 31
+
+    defaultConfig {
+        minSdk = 28
+        targetSdk = 31
+        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+    }
+
+    buildTypes {
+        release {
+            isMinifyEnabled = false
+            proguardFiles(
+                getDefaultProguardFile("proguard-android-optimize.txt"),
+                "proguard-rules.pro"
+            )
+        }
+    }
+
+    compileOptions {
+        sourceCompatibility = JavaVersion.VERSION_1_8
+        targetCompatibility = JavaVersion.VERSION_1_8
+    }
+
+    kotlinOptions {
+        jvmTarget = "1.8"
+    }
+}
+
+dependencies {
+
+    implementation("androidx.core:core-ktx:1.7.0")
+    implementation("androidx.appcompat:appcompat:1.4.0")
+    implementation("com.google.android.material:material:1.4.0")
+    implementation("com.google.zxing:core:3.3.0")
+    //implementation("cn.sagacloud:saga-kotlin-base:1.4.105")
+    //implementation("pub.devrel:easypermissions:1.2.0")
+
+    testImplementation("junit:junit:4.13.2")
+    androidTestImplementation("androidx.test.ext:junit:1.1.3")
+    androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
+}

+ 21 - 0
adm-base/proguard-rules.pro

@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile

+ 24 - 0
adm-base/src/androidTest/java/com/ys/bdtp/base/ExampleInstrumentedTest.kt

@@ -0,0 +1,24 @@
+package com.ys.bdtp.base
+
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.ext.junit.runners.AndroidJUnit4
+
+import org.junit.Test
+import org.junit.runner.RunWith
+
+import org.junit.Assert.*
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+@RunWith(AndroidJUnit4::class)
+class ExampleInstrumentedTest {
+    @Test
+    fun useAppContext() {
+        // Context of the app under test.
+        val appContext = InstrumentationRegistry.getInstrumentation().targetContext
+        assertEquals("com.ys.bdtp.base.test", appContext.packageName)
+    }
+}

+ 5 - 0
adm-base/src/main/AndroidManifest.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          package="com.ys.bdtp.base">
+
+</manifest>

+ 41 - 0
adm-base/src/main/java/com/ys/bdtp/base/SApplication.kt

@@ -0,0 +1,41 @@
+package com.ys.bdtp.base
+
+import android.app.Application
+import android.app.Service
+import android.os.Vibrator
+import com.ys.bdtp.base.services.SVibratorService
+
+/**
+ * 斯伯坦机器人android应用程序对象
+ *
+ * @author  庞利祥(sybotan@126.com)
+ */
+open class SApplication : Application() {
+    /** 类静态成员 */
+    companion object {
+        /** 应用程序对象 */
+        lateinit var app: SApplication
+    } // companion object
+
+    /** 数据库版本 */
+    var databaseVersion: Int = 1
+
+    /**
+     * 主构造函数
+     */
+    init {
+        app = this
+    } // init
+
+    /**
+     * 创建应用时调用
+     */
+    override fun onCreate() {
+        super.onCreate()
+
+        // 初始化震动器
+        SVibratorService.vibrator = getSystemService(Service.VIBRATOR_SERVICE) as Vibrator
+
+        return
+    }// Function onCreate()
+} // Class SApplication

+ 120 - 0
adm-base/src/main/java/com/ys/bdtp/base/SOptions.kt

@@ -0,0 +1,120 @@
+
+package com.ys.bdtp.base
+
+import android.content.SharedPreferences
+import org.jetbrains.anko.defaultSharedPreferences
+
+/**
+ * 保存应用系统设置
+ *
+ * @author  庞利祥(sybotan@126.com)
+ */
+open class SOptions {
+    /** 共享存储对象 */
+    private var pref: SharedPreferences = SApplication.app.defaultSharedPreferences
+
+    /**
+     * 获得Boolean类型的值
+     *
+     * @param   key         键
+     * @param   default     默认值
+     */
+    fun getBoolean(key: String, default: Boolean): Boolean {
+        return pref.getBoolean(key, default)
+    } // Function getBoolean()
+
+    /**
+     * 设置Boolean类型的值
+     *
+     * @param   key         键
+     * @param   value       值
+     */
+    fun putBoolean(key: String, value: Boolean) {
+        pref.edit().putBoolean(key, value).apply()
+        return
+    } // Function putBoolean()
+
+    /**
+     * 获得Float类型的值
+     *
+     * @param   key         键
+     * @param   default     默认值
+     */
+    fun getFloat(key: String, default: Float): Float {
+        return pref.getFloat(key, default)
+    } // Function getFloat()
+
+    /**
+     * 设置Float类型的值
+     *
+     * @param   key         键
+     * @param   value       值
+     */
+    fun putFloat(key: String, value: Float) {
+        pref.edit().putFloat(key, value).apply()
+        return
+    } // Function putFloat()
+
+    /**
+     * 获得Int类型的值
+     *
+     * @param   key         键
+     * @param   default     默认值
+     */
+    fun getInt(key: String, default: Int): Int {
+        return pref.getInt(key, default)
+    } // Function getInt()
+
+    /**
+     * 设置Int类型的值
+     *
+     * @param   key         键
+     * @param   value       值
+     */
+    fun putInt(key: String, value: Int) {
+        pref.edit().putInt(key, value).apply()
+        return
+    } // Function putInt()
+
+    /**
+     * 获得Long类型的值
+     *
+     * @param   key         键
+     * @param   default     默认值
+     */
+    fun getLong(key: String, default: Long): Long {
+        return pref.getLong(key, default)
+    } // Function getLong()
+
+    /**
+     * 设置Long类型的值
+     *
+     * @param   key         键
+     * @param   value       值
+     */
+    fun putLong(key: String, value: Long) {
+        pref.edit().putLong(key, value).apply()
+        return
+    } // Function putLong()
+
+    /**
+     * 获得String类型的值
+     *
+     * @param   key         键
+     * @param   default     默认值
+     */
+    fun getString(key: String, default: String): String {
+        return pref.getString(key, default)!!
+    } // Function getString()
+
+    /**
+     * 设置String类型的值
+     *
+     * @param   key         键
+     * @param   value       值
+     */
+    fun putString(key: String, value: String) {
+        pref.edit().putString(key, value).apply()
+        return
+    } // Function putString()
+} // Class SOptions

+ 77 - 0
adm-base/src/main/java/com/ys/bdtp/base/activities/SBaseActivity.kt

@@ -0,0 +1,77 @@
+package com.ys.bdtp.base.activities
+
+import androidx.appcompat.app.AppCompatActivity
+import org.jetbrains.anko.toast
+import pub.devrel.easypermissions.AppSettingsDialog
+import pub.devrel.easypermissions.EasyPermissions
+
+/**
+ * Activity基类
+ *
+ * @author  庞利祥(sybotan@126.com)
+ */
+open class SBaseActivity : AppCompatActivity(), EasyPermissions.PermissionCallbacks {
+
+
+    /**
+     * 申请权限
+     *
+     * @param   permissionList      权限列表
+     * @param   requestCode         请求码
+     */
+    fun requestPermission(permissionList: Array<String>, requestCode: Int = 1) {
+        // 如果没有获得相应的权限
+        if (!EasyPermissions.hasPermissions(this, *permissionList)) {
+            // 申请权限
+            EasyPermissions.requestPermissions(this, "", requestCode, *permissionList)
+        }
+
+        return
+    } // Function requestPermission()
+
+    /**
+     * 用户授权成功回调
+     *
+     * @param   requestCode     请求码
+     * @param   perms           请求权限列表
+     */
+    override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
+        toast("用户授权失败!")
+        /**
+         * 若是在权限弹窗中,用户勾选了'NEVER ASK AGAIN.'或者'不在提示',且拒绝权限。
+         * 这时候,需要跳转到设置界面去,让用户手动开启。
+         */
+        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
+            AppSettingsDialog.Builder(this)
+                .setRationale("此功能需要权限,否则无法正常使用,是否打开设置")
+                .setPositiveButton("是")
+                .setNegativeButton("否")
+                .build()
+                .show()
+        }
+    } // Function onPermissionsDenied()
+
+    /**
+     * 用户授权成功回调
+     *
+     * @param   requestCode     请求码
+     * @param   perms           请求权限列表
+     */
+    override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {
+        toast("用户授权成功!")
+        return
+    } // Function onPermissionsGranted()
+
+    /**
+     * 请求权限结果
+     *
+     * @param   requestCode     请求码
+     * @param   permissions     请求权限列表
+     * @param   grantResults    授权结果
+     */
+    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
+        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+        EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
+        return
+    } // Function onRequestPermissionsResult()
+} // Class SBaseActivity()

+ 98 - 0
adm-base/src/main/java/com/ys/bdtp/base/comparators/SFileComparator.kt

@@ -0,0 +1,98 @@
+package com.ys.bdtp.base.comparators
+
+import java.io.File
+
+/**
+ * 文件排序器
+ *
+ * @author  庞利祥(sybotan@126.com)
+ */
+class SFileComparator {
+    /**
+     * 名称升序比较器
+     *
+     * @author  庞利祥(sybotan@126.com)
+     */
+    class NameAsc : Comparator<File> {
+        /**
+         * 文件名比较
+         *
+         * @param   file1   文件1
+         * @param   file2   文件2
+         * @return  如果文件1比文件2名称靠后返回1,否则返回-1
+         */
+        override fun compare(file1: File, file2: File): Int {
+            return if (file1.name > file2.name) {
+                1
+            } else {
+                -1
+            }
+        } // Function compare()
+    } // LastModifiedAsc
+
+    /**
+     * 文件名比较器
+     *
+     * @author  庞利祥(sybotan@126.com)
+     */
+    class NameDesc : Comparator<File> {
+        /**
+         * 创建时间比较
+         *
+         * @param   file1   文件1
+         * @param   file2   文件2
+         * @return  如果文件1比文件2名称靠前返回1,否则返回-1
+         */
+        override fun compare(file1: File, file2: File): Int {
+            return if (file1.name < file2.name) {
+                1
+            } else {
+                -1
+            }
+        } // Function compare()
+    } // NameDesc
+
+    /**
+     * 创建时间升序比较器
+     *
+     * @author  庞利祥(sybotan@126.com)
+     */
+    class LastModifiedAsc : Comparator<File> {
+        /**
+         * 创建时间比较
+         *
+         * @param   file1   文件1
+         * @param   file2   文件2
+         * @return  如果文件1比文件2修改时间靠后返回1,否则返回-1
+         */
+        override fun compare(file1: File, file2: File): Int {
+            return if (file1.lastModified() > file2.lastModified()) {
+                1
+            } else {
+                -1
+            }
+        } // Function compare()
+    } // LastModifiedAsc
+
+    /**
+     * 创建时间降序比较器
+     *
+     * @author  庞利祥(sybotan@126.com)
+     */
+    class LastModifiedDesc : Comparator<File> {
+        /**
+         * 创建时间比较
+         *
+         * @param   file1   文件1
+         * @param   file2   文件2
+         * @return  如果文件1比文件2修改时间靠前返回1,否则返回-1
+         */
+        override fun compare(file1: File, file2: File): Int {
+            return if (file1.lastModified() < file2.lastModified()) {
+                1
+            } else {
+                -1
+            }
+        } // Function compare()
+    } // LastModifiedDesc
+} // Class SFileComparator

+ 20 - 0
adm-base/src/main/java/com/ys/bdtp/base/comparators/SSizesByAreaComparator.kt

@@ -0,0 +1,20 @@
+package com.ys.bdtp.base.comparators
+
+import android.util.Size
+
+/**
+ * 区域大小比较器
+ *
+ * @author  庞利祥(sybotan@126.com)
+ */
+class SSizesByAreaComparator : Comparator<Size> {
+    /**
+     * 判断区域lhs是否比rhs大
+     *
+     * @param   lhs     比较区域1
+     * @param   rhs     比较区域2
+     */
+    override fun compare(lhs: Size, rhs: Size): Int {
+        return java.lang.Long.signum(lhs.width.toLong() * lhs.height - rhs.width.toLong() * rhs.height)
+    } // Function compare()
+} // Class SSizesByAreaComparator()

+ 26 - 0
adm-base/src/main/java/com/ys/bdtp/base/extensions/SActivityExtension.kt

@@ -0,0 +1,26 @@
+
+package com.ys.bdtp.base.extensions
+
+import android.app.Activity
+import android.graphics.Color
+import android.view.View
+
+/**
+ * 全屏沉浸
+ */
+fun Activity.immersive() {
+    window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION  or View.SYSTEM_UI_FLAG_IMMERSIVE or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+    window.navigationBarColor = Color.TRANSPARENT
+    window.statusBarColor = Color.TRANSPARENT
+    return
+} // Function Activity.immersive()
+
+/**
+ * 粘性沉浸
+ */
+fun Activity.immersiveSticky() {
+    window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION  or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+    window.navigationBarColor = Color.TRANSPARENT
+    window.statusBarColor = Color.TRANSPARENT
+    return
+} // Function Activity.immersiveSticky()

+ 19 - 0
adm-base/src/main/java/com/ys/bdtp/base/extensions/SMenuExtension.kt

@@ -0,0 +1,19 @@
+package com.ys.bdtp.base.extensions
+
+import android.view.Menu
+import android.view.MenuItem
+
+/**
+ * Menu扩展indexOf函数
+ *
+ * @param   item    查询item
+ * @return  item索引,不存在返回-1
+ */
+fun Menu.indexOf(item: MenuItem): Int {
+    for (i in 0 until size()) {
+        if (this.getItem(i) === item) {
+            return i
+        }
+    }
+    return -1
+} // Function Menu.indexO()

+ 64 - 0
adm-base/src/main/java/com/ys/bdtp/base/extensions/SPathExtension.kt

@@ -0,0 +1,64 @@
+package com.ys.bdtp.base.extensions
+
+import android.graphics.Path
+
+/**
+ * 为Path扩展logo接口
+ *
+ * @return  logo的Path路径
+ */
+fun Path.logo(zoom: Float = 1f): Path {
+
+    val p1 = Path()
+    p1.addCircle(0f * zoom, 20f * zoom, 30f * zoom, Path.Direction.CCW)
+    val headPath = Path()
+    headPath.addCircle(0f * zoom, 0f * zoom, 50f * zoom, Path.Direction.CCW)
+    headPath.op(p1, Path.Op.DIFFERENCE)
+
+    val bodyPath = Path()
+    bodyPath.rLineTo(40f * zoom, -20f * zoom)
+    bodyPath.rLineTo(0f * zoom, 110f * zoom)
+    bodyPath.rLineTo(-10f * zoom, 30f * zoom)
+    bodyPath.rLineTo(-30f * zoom, 40f * zoom)
+    bodyPath.rLineTo(-30f * zoom, -40f * zoom)
+    bodyPath.rLineTo(-10f * zoom, -30f * zoom)
+    bodyPath.rLineTo(0f * zoom, -110f * zoom)
+    bodyPath.close()
+
+    val leftPath = Path()
+    leftPath.rLineTo(0f * zoom, 120f * zoom)
+    leftPath.rLineTo(20f * zoom, 50f * zoom)
+    leftPath.rLineTo(-90f * zoom, -60f * zoom)
+    leftPath.rLineTo(-10f * zoom, -30f * zoom)
+    leftPath.rLineTo(50f * zoom, 25f * zoom)
+    leftPath.rLineTo(0f * zoom, -20f * zoom)
+    leftPath.rLineTo(-50f * zoom, -25f * zoom)
+    leftPath.rLineTo(0f * zoom, -40f * zoom)
+    leftPath.rLineTo(50f * zoom, 25f * zoom)
+    leftPath.rLineTo(0f * zoom, -20f * zoom)
+    leftPath.rLineTo(-50f * zoom, -25f * zoom)
+    leftPath.rLineTo(0f * zoom, -40f * zoom)
+    leftPath.close()
+
+    val rightPath = Path()
+    rightPath.rLineTo(0f * zoom, 120f * zoom)
+    rightPath.rLineTo(-20f * zoom, 50f * zoom)
+    rightPath.rLineTo(90f * zoom, -60f * zoom)
+    rightPath.rLineTo(10f * zoom, -30f * zoom)
+    rightPath.rLineTo(-50f * zoom, 25f * zoom)
+    rightPath.rLineTo(0f * zoom, -20f * zoom)
+    rightPath.rLineTo(50f * zoom, -25f * zoom)
+    rightPath.rLineTo(0f * zoom, -40f * zoom)
+    rightPath.rLineTo(-50f * zoom, 25f * zoom)
+    rightPath.rLineTo(0f * zoom, -20f * zoom)
+    rightPath.rLineTo(50f * zoom, -25f * zoom)
+    rightPath.rLineTo(0f * zoom, -40f * zoom)
+    rightPath.close()
+
+    val logoPath = Path()
+    logoPath.addPath(headPath, 0f * zoom, -90f * zoom)
+    logoPath.addPath(bodyPath, 0f * zoom, -20f * zoom)
+    logoPath.addPath(leftPath, -60f * zoom, -50f * zoom)
+    logoPath.addPath(rightPath, 60f * zoom, -50f * zoom)
+    return logoPath
+} // Function logo()

+ 25 - 0
adm-base/src/main/java/com/ys/bdtp/base/extensions/SRectExtension.kt

@@ -0,0 +1,25 @@
+package com.ys.bdtp.base.extensions
+
+import android.graphics.Point
+import android.graphics.Rect
+
+/**
+ * RectF位置移dx,dy
+ *
+ * @param   dx          横向移动的距离
+ * @param   dy          纵向移动的距离
+ * @return  移动后的RectF
+ */
+fun Rect.adjusted(dx: Int, dy: Int): Rect {
+    return Rect(this.left + dx, this.top + dy, this.right + dx, this.bottom + dy)
+} // Function adjusted()
+
+/**
+ * RectF位置移offset
+ *
+ * @param   offset      移动偏移量
+ * @return  移动后的RectF
+ */
+fun Rect.adjusted(offset: Point): Rect {
+    return adjusted(offset.x, offset.y)
+} // Function adjusted()

+ 25 - 0
adm-base/src/main/java/com/ys/bdtp/base/extensions/SRectFExtension.kt

@@ -0,0 +1,25 @@
+package com.ys.bdtp.base.extensions
+
+import android.graphics.PointF
+import android.graphics.RectF
+
+/**
+ * RectF位置移dx,dy
+ *
+ * @param   dx          横向移动的距离
+ * @param   dy          纵向移动的距离
+ * @return  移动后的RectF
+ */
+fun RectF.adjusted(dx: Float, dy: Float): RectF {
+    return RectF(this.left + dx, this.top + dy, this.right + dx, this.bottom + dy)
+} // Function adjusted()
+
+/**
+ * RectF位置移offset
+ *
+ * @param   offset      移动偏移量
+ * @return  移动后的RectF
+ */
+fun RectF.adjusted(offset: PointF): RectF {
+    return adjusted(offset.x, offset.y)
+} // Function adjusted()

+ 20 - 0
adm-base/src/main/java/com/ys/bdtp/base/extensions/SWebResourceRequestExtension.kt

@@ -0,0 +1,20 @@
+package com.ys.bdtp.base.extensions
+
+import android.webkit.WebResourceRequest
+import java.util.regex.Pattern
+
+/**
+ * 获得请求参数
+ *
+ * @param   name        参数名称
+ * @return  参数的值
+ */
+fun WebResourceRequest.param(name: String): String {
+    var ret = ""
+    val p = Pattern.compile("[&?]$name=([^&]*)(&|$)")
+    val m = p.matcher(this.url.toString())
+    while (m.find()) {
+        ret = m.group(1)
+    }
+    return ret
+} // Function param()

+ 34 - 0
adm-base/src/main/java/com/ys/bdtp/base/services/SVibratorService.kt

@@ -0,0 +1,34 @@
+package com.ys.bdtp.base.services
+
+import android.os.Build
+import android.os.VibrationEffect
+import android.os.Vibrator
+
+/**
+ * 震动器服务对象
+ *
+ * @author  庞利祥(sybotan@126.com)
+ */
+object SVibratorService {
+    /** 震动器 */
+    var vibrator: Vibrator? = null
+
+    /**
+     * 震动器震动
+     *
+     * @param   millisecond     震动时间,单位毫秒*
+     */
+    fun vibrate(millisecond: Long, amplitude: Int = 128) {
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {           // API 26 以上使用以下代码
+            val vibrationEffect  = VibrationEffect.createOneShot(millisecond, amplitude)
+            vibrator?.vibrate(vibrationEffect)
+        } else {
+            vibrator?.vibrate(millisecond)
+        }
+
+
+        return
+    } // Function vibrate()
+
+} // Class SVibratorService

+ 33 - 0
adm-base/src/main/java/com/ys/bdtp/base/utils/SKeyboardUtil.kt

@@ -0,0 +1,33 @@
+package com.ys.bdtp.base.utils
+
+import android.app.Activity
+import android.content.Context.INPUT_METHOD_SERVICE
+import android.view.inputmethod.InputMethodManager
+
+
+/**
+ * Android软键盘工具类
+ *
+ * @author  庞利祥(sybotan@126.com)
+ */
+object SKeyboardUtil {
+    /**
+     * 隐藏键盘
+     *
+     * @param   activity     当前activity对象
+     */
+    fun dismissSoftKeyboard(activity: Activity): Boolean {
+        try {
+            val inputMethodManage = activity.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
+            return if (activity.currentFocus == null) {
+                inputMethodManage.hideSoftInputFromWindow(activity.window.decorView.windowToken, 0)
+            } else {
+                inputMethodManage.hideSoftInputFromWindow(activity.currentFocus!!.windowToken, 0)
+            }
+        } catch (e: Exception) {
+            e.printStackTrace()
+        }
+
+        return false
+    } // Function dismissSoftKeyboard()
+} // Object SKeyboardUtil

+ 120 - 0
adm-base/src/main/java/com/ys/bdtp/base/utils/SQrCodeUtil.kt

@@ -0,0 +1,120 @@
+package com.ys.bdtp.base.utils
+
+import android.graphics.*
+import android.webkit.JavascriptInterface
+import com.google.zxing.*
+import com.google.zxing.common.HybridBinarizer
+import com.google.zxing.qrcode.QRCodeReader
+import com.google.zxing.qrcode.QRCodeWriter
+import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
+import java.util.*
+
+/**
+ * 二维码生成工具
+ *
+ * @author  庞利祥(sybotan@126.com)
+ */
+object SQrCodeUtil {
+
+    /** 背景颜色 */
+    var bgColor = 0xFFFFFFFF.toInt()
+
+    /** 前景颜色 */
+    var pixelColor = 0xFF000000.toInt()
+
+    /**
+     * 创建二维码图像
+     *
+     * @param   contents        二维码存储的内容
+     * @param   size            二维码大小
+     * @return  二维码图像
+     */
+    @JavascriptInterface
+    fun createQrCode(contents: String, size: Int, logo: Bitmap? = null): Bitmap? {
+        try {
+            val hints = Hashtable<EncodeHintType, Any>()
+            hints[EncodeHintType.CHARACTER_SET] = "utf-8"
+            hints[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.H
+
+            val matrix = QRCodeWriter().encode(contents, BarcodeFormat.QR_CODE, size, size, hints)
+            var image = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
+
+            for (y in 0 until size) {
+                for (x in 0 until size) {
+                    if (matrix.get(x, y)) {
+                        image.setPixel(x, y, pixelColor)
+                    } else {
+                        image.setPixel(x, y, bgColor)
+                    }
+                }
+            }
+
+            if (null != logo) {
+                image = addLogo(image, logo)
+            }
+
+            return image
+        } catch (e: WriterException) {
+            e.printStackTrace()
+        }
+        return null
+    } // Function createQrCode()
+
+    /**
+     * 解析二维码图片
+     *
+     * @param   bitmap      二维码图片
+     * @return  解析结果
+     */
+    fun decodeQrCode(bitmap: Bitmap): String? {
+        val width = bitmap.width
+        val height = bitmap.height
+        val pixels = IntArray(width * height)
+        bitmap.getPixels(pixels, 0, width, 0, 0, width, height)
+        val luminanceSource = RGBLuminanceSource(width, height, pixels)
+        val binaryBitmap = BinaryBitmap(HybridBinarizer(luminanceSource))
+        return decodeQrCode(binaryBitmap)
+    } // Function decode()
+
+    /**
+     * 解析二维码
+     *
+     * @param   binaryBitmap    被解析的图形对象
+     * @return  解析的结果
+     */
+    fun decodeQrCode(binaryBitmap: BinaryBitmap): String? {
+        return try {
+            val hints = HashMap<DecodeHintType, Any>()
+            hints[DecodeHintType.CHARACTER_SET] = "utf-8"
+            hints[DecodeHintType.TRY_HARDER] = true
+            hints[DecodeHintType.POSSIBLE_FORMATS] = BarcodeFormat.QR_CODE
+            val result = QRCodeReader().decode(binaryBitmap, hints)
+            result.text
+        } catch (e: Exception) {
+            e.printStackTrace()
+            null
+        }
+    } // Function decode()
+
+    /**
+     * 为二维码图片增加Logo
+     *
+     * @param   src         二维码图片
+     * @param   logo        Logol图片
+     * @return  添加过Logo的二维码图片
+     */
+    private fun addLogo(src: Bitmap, logo: Bitmap): Bitmap {
+        val srcWidth = src.width
+        val srcHeight = src.height
+
+        val image = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888)
+        val canvas = Canvas(image)
+        canvas.drawBitmap(src, 0f, 0f, null)
+        canvas.drawBitmap(
+            logo, Rect(0, 0, srcWidth, srcHeight),
+            RectF(srcWidth * 2 / 5f, srcHeight * 2 / 5f, srcWidth * 3 / 5f, srcHeight * 3 / 5f), null
+        )
+
+        return image
+    } // Function addLogo()
+} // Object QrCodeUntil

+ 17 - 0
adm-base/src/test/java/com/ys/bdtp/base/ExampleUnitTest.kt

@@ -0,0 +1,17 @@
+package com.ys.bdtp.base
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+    @Test
+    fun addition_isCorrect() {
+        assertEquals(4, 2 + 2)
+    }
+}