____ _ _______ __
/ __ \ | /| / / __/ |/ /
/ /_/ / |/ |/ / _// /
\____/|__/|__/___/_||_/
owenclave / app/src/main/java/io/nekohasekai/sagernet/widget/QRCodeDialog.kt
/******************************************************************************
* *
* Copyright (C) 2021 by nekohasekai *
* Copyright (C) 2021 by Max Lv *
* Copyright (C) 2021 by Mygod Studio *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
* *
******************************************************************************/
package io.nekohasekai.sagernet.widget
import android.graphics.Bitmap
import android.graphics.Color
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.WriterException
import com.google.zxing.qrcode.QRCodeWriter
import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.ktx.Logs
import io.nekohasekai.sagernet.ktx.app
import io.nekohasekai.sagernet.ktx.readableMessage
import io.nekohasekai.sagernet.ui.MainActivity
import java.nio.charset.StandardCharsets
import kotlin.math.roundToInt
class QRCodeDialog() : DialogFragment() {
companion object {
private const val KEY_URL = "io.nekohasekai.sagernet.QRCodeDialog.KEY_URL"
private val iso88591 = StandardCharsets.ISO_8859_1.newEncoder()
private val size by lazy {
try {
val displayMetrics: DisplayMetrics = app.resources.displayMetrics
val height: Int = displayMetrics.heightPixels
val width: Int = displayMetrics.widthPixels
((if (height > width) width else height) * 0.8).roundToInt()
} catch (e: Exception) {
Logs.w(e)
app.resources.getDimensionPixelSize(R.dimen.qrcode_size)
}
}
}
constructor(url: String) : this() {
arguments = bundleOf(Pair(KEY_URL, url))
}
/**
* Based on:
* https://android.googlesource.com/platform/
packages/apps/Settings/+/0d706f0/src/com/android/settings/wifi/qrcode/QrCodeGenerator.java
* https://android.googlesource.com/platform/
packages/apps/Settings/+/8a9ccfd/src/com/android/settings/wifi/dpp/WifiDppQrCodeGeneratorFragment.java#153
*/
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?) = try {
val url = arguments?.getString(KEY_URL)!!
val hints = mutableMapOf()
if (!iso88591.canEncode(url)) hints[EncodeHintType.CHARACTER_SET] = StandardCharsets.UTF_8.name()
val qrBits = QRCodeWriter().encode(url, BarcodeFormat.QR_CODE, size, size, hints)
ImageView(context).apply {
layoutParams = ViewGroup.LayoutParams(size, size)
setImageBitmap(Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565).apply {
for (x in 0 until size) for (y in 0 until size) {
setPixel(x, y, if (qrBits.get(x, y)) Color.BLACK else Color.WHITE)
}
})
}
} catch (e: WriterException) {
Logs.w(e)
(activity as MainActivity).snackbar(e.readableMessage).show()
dismiss()
null
}
}