Added lock
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
package xyz.quaver.pupil.ui
|
||||
|
||||
import android.app.Activity
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import android.os.Bundle
|
||||
import android.widget.Toast
|
||||
import com.andrognito.patternlockview.PatternLockView
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import kotlinx.android.synthetic.main.activity_lock.*
|
||||
import kotlinx.android.synthetic.main.fragment_pattern_lock.*
|
||||
import kotlinx.android.synthetic.main.settings_activity.*
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.util.Lock
|
||||
import xyz.quaver.pupil.util.LockManager
|
||||
|
||||
class LockActivity : AppCompatActivity() {
|
||||
|
||||
@@ -12,18 +19,67 @@ class LockActivity : AppCompatActivity() {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_lock)
|
||||
|
||||
val lockManager = LockManager(this)
|
||||
|
||||
val mode = intent.getStringExtra("mode")
|
||||
|
||||
lock_pattern.isEnabled = false
|
||||
lock_pin.isEnabled = false
|
||||
lock_fingerprint.isEnabled = false
|
||||
lock_password.isEnabled = false
|
||||
|
||||
when(mode) {
|
||||
null -> {
|
||||
if (lockManager.empty()) {
|
||||
setResult(RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
"add_lock" -> {
|
||||
when(intent.getStringExtra("type")!!) {
|
||||
"pattern" -> {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
supportFragmentManager.beginTransaction().add(
|
||||
R.id.lock_content,
|
||||
PatternLockFragment().apply {
|
||||
var lastPass = ""
|
||||
onPatternDrawn = {
|
||||
Toast.makeText(context, it, Toast.LENGTH_SHORT).show()
|
||||
when(mode) {
|
||||
null -> {
|
||||
val result = lockManager.check(it)
|
||||
|
||||
if (result == true) {
|
||||
setResult(Activity.RESULT_OK)
|
||||
finish()
|
||||
} else
|
||||
lock_pattern_view.setViewMode(PatternLockView.PatternViewMode.WRONG)
|
||||
}
|
||||
"add_lock" -> {
|
||||
if (lastPass.isEmpty()) {
|
||||
lastPass = it
|
||||
|
||||
Snackbar.make(view!!, R.string.settings_lock_confirm, Snackbar.LENGTH_LONG).show()
|
||||
} else {
|
||||
if (lastPass == it) {
|
||||
LockManager(context!!).add(Lock.generate(Lock.Type.PATTERN, it))
|
||||
finish()
|
||||
} else {
|
||||
lock_pattern_view.setViewMode(PatternLockView.PatternViewMode.WRONG)
|
||||
lastPass = ""
|
||||
|
||||
Snackbar.make(view!!, R.string.settings_lock_wrong_confirm, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
).commit()
|
||||
|
||||
lock_pattern.isEnabled = false
|
||||
lock_fingerprint.isEnabled = false
|
||||
lock_password.isEnabled = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package xyz.quaver.pupil.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.drawable.Animatable
|
||||
@@ -76,7 +77,8 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
private var mode = Mode.SEARCH
|
||||
|
||||
private val SETTINGS = 45162
|
||||
private val REQUEST_SETTINGS = 45162
|
||||
private val REQUEST_LOCK = 561
|
||||
|
||||
private var galleryIDs: Deferred<List<Int>>? = null
|
||||
private var totalItems = 0
|
||||
@@ -90,6 +92,8 @@ class MainActivity : AppCompatActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
startActivityForResult(Intent(this, LockActivity::class.java), REQUEST_LOCK)
|
||||
|
||||
checkPermissions()
|
||||
|
||||
val preference = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
@@ -143,6 +147,7 @@ class MainActivity : AppCompatActivity() {
|
||||
WindowManager.LayoutParams.FLAG_SECURE)
|
||||
else
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
@@ -187,7 +192,7 @@ class MainActivity : AppCompatActivity() {
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
when(requestCode) {
|
||||
SETTINGS -> {
|
||||
REQUEST_SETTINGS -> {
|
||||
runOnUiThread {
|
||||
cancelFetch()
|
||||
clearGalleries()
|
||||
@@ -195,6 +200,10 @@ class MainActivity : AppCompatActivity() {
|
||||
loadBlocks()
|
||||
}
|
||||
}
|
||||
REQUEST_LOCK -> {
|
||||
if (resultCode != Activity.RESULT_OK)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -679,7 +688,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
setOnMenuItemClickListener {
|
||||
when(it.itemId) {
|
||||
R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), SETTINGS)
|
||||
R.id.main_menu_settings -> startActivityForResult(Intent(this@MainActivity, SettingsActivity::class.java), REQUEST_SETTINGS)
|
||||
R.id.main_menu_jump -> {
|
||||
val preference = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val perPage = preference.getString("per_page", "25")!!.toInt()
|
||||
|
||||
@@ -12,6 +12,7 @@ import kotlinx.android.synthetic.main.fragment_pattern_lock.*
|
||||
import kotlinx.android.synthetic.main.fragment_pattern_lock.view.*
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.util.hash
|
||||
import xyz.quaver.pupil.util.hashWithSalt
|
||||
|
||||
class PatternLockFragment : Fragment(), PatternLockViewListener {
|
||||
|
||||
@@ -32,7 +33,7 @@ class PatternLockFragment : Fragment(), PatternLockViewListener {
|
||||
|
||||
override fun onComplete(pattern: MutableList<PatternLockView.Dot>?) {
|
||||
val password = PatternLockUtils.patternToMD5(lock_pattern_view, pattern)
|
||||
onPatternDrawn?.invoke(hash(password))
|
||||
onPatternDrawn?.invoke(password)
|
||||
}
|
||||
|
||||
override fun onProgress(progressPattern: MutableList<PatternLockView.Dot>?) {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package xyz.quaver.pupil.ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
@@ -14,14 +16,17 @@ import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import androidx.preference.PreferenceManager
|
||||
import io.fabric.sdk.android.BuildConfig
|
||||
import kotlinx.android.synthetic.main.dialog_default_query.view.*
|
||||
import xyz.quaver.pupil.R
|
||||
import xyz.quaver.pupil.types.Tags
|
||||
import xyz.quaver.pupil.util.Lock
|
||||
import xyz.quaver.pupil.util.LockManager
|
||||
import java.io.File
|
||||
|
||||
class SettingsActivity : AppCompatActivity() {
|
||||
|
||||
val REQUEST_LOCK = 38238
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
@@ -59,6 +64,24 @@ class SettingsActivity : AppCompatActivity() {
|
||||
"TB" //really?
|
||||
)
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
val lockManager = LockManager(context!!)
|
||||
|
||||
findPreference<Preference>("app_lock")?.summary = if (lockManager.locks.isNullOrEmpty()) {
|
||||
getString(R.string.settings_lock_none)
|
||||
} else {
|
||||
lockManager.locks?.joinToString(", ") {
|
||||
when(it.type) {
|
||||
Lock.Type.PATTERN -> getString(R.string.settings_lock_pattern)
|
||||
Lock.Type.PIN -> getString(R.string.settings_lock_pin)
|
||||
Lock.Type.PASSWORD -> getString(R.string.settings_lock_password)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDirSize(dir: File) : String {
|
||||
var size = dir.walk().map { it.length() }.sum()
|
||||
var suffixIndex = 0
|
||||
@@ -75,7 +98,7 @@ class SettingsActivity : AppCompatActivity() {
|
||||
setPreferencesFromResource(R.xml.root_preferences, rootKey)
|
||||
|
||||
with(findPreference<Preference>("app_version")) {
|
||||
this ?: return@with
|
||||
this!!
|
||||
|
||||
val manager = context.packageManager
|
||||
val info = manager.getPackageInfo(context.packageName, 0)
|
||||
@@ -84,7 +107,7 @@ class SettingsActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
with(findPreference<Preference>("delete_cache")) {
|
||||
this ?: return@with
|
||||
this!!
|
||||
|
||||
val dir = File(context.cacheDir, "imageCache")
|
||||
|
||||
@@ -108,7 +131,7 @@ class SettingsActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
with(findPreference<Preference>("delete_downloads")) {
|
||||
this ?: return@with
|
||||
this!!
|
||||
|
||||
val dir = context.getExternalFilesDir("Pupil") ?: return@with
|
||||
|
||||
@@ -135,7 +158,7 @@ class SettingsActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
with(findPreference<Preference>("clear_history")) {
|
||||
this ?: return@with
|
||||
this!!
|
||||
|
||||
val histories = (activity!!.application as Pupil).histories
|
||||
|
||||
@@ -157,7 +180,7 @@ class SettingsActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
with(findPreference<Preference>("default_query")) {
|
||||
this ?: return@with
|
||||
this!!
|
||||
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
@@ -272,7 +295,80 @@ class SettingsActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
with(findPreference<Preference>("app_lock")) {
|
||||
this!!
|
||||
|
||||
val lockManager = LockManager(context)
|
||||
|
||||
summary = if (lockManager.locks.isNullOrEmpty()) {
|
||||
getString(R.string.settings_lock_none)
|
||||
} else {
|
||||
lockManager.locks?.joinToString(", ") {
|
||||
when(it.type) {
|
||||
Lock.Type.PATTERN -> getString(R.string.settings_lock_pattern)
|
||||
Lock.Type.PIN -> getString(R.string.settings_lock_pin)
|
||||
Lock.Type.PASSWORD -> getString(R.string.settings_lock_password)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
val intent = Intent(context, LockActivity::class.java)
|
||||
activity?.startActivityForResult(intent, (activity as SettingsActivity).REQUEST_LOCK)
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class LockFragment : PreferenceFragmentCompat() {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
val lockManager = LockManager(context!!)
|
||||
|
||||
findPreference<Preference>("lock_pattern")?.summary =
|
||||
if (lockManager.contains(Lock.Type.PATTERN))
|
||||
getString(R.string.settings_lock_enabled)
|
||||
else
|
||||
""
|
||||
}
|
||||
|
||||
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||
setPreferencesFromResource(R.xml.lock_preferences, rootKey)
|
||||
|
||||
with(findPreference<Preference>("lock_pattern")) {
|
||||
this!!
|
||||
|
||||
if (LockManager(context!!).contains(Lock.Type.PATTERN))
|
||||
summary = getString(R.string.settings_lock_enabled)
|
||||
|
||||
onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
val lockManager = LockManager(context!!)
|
||||
|
||||
if (lockManager.contains(Lock.Type.PATTERN)) {
|
||||
AlertDialog.Builder(context).apply {
|
||||
setTitle(R.string.warning)
|
||||
setMessage(R.string.settings_lock_remove_message)
|
||||
|
||||
setPositiveButton(android.R.string.yes) { _, _ ->
|
||||
lockManager.remove(Lock.Type.PATTERN)
|
||||
onResume()
|
||||
}
|
||||
setNegativeButton(android.R.string.no) { _, _ -> }
|
||||
}.show()
|
||||
} else {
|
||||
val intent = Intent(context, LockActivity::class.java).apply {
|
||||
putExtra("mode", "add_lock")
|
||||
putExtra("type", "pattern")
|
||||
}
|
||||
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,4 +380,19 @@ class SettingsActivity : AppCompatActivity() {
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
when(requestCode) {
|
||||
REQUEST_LOCK -> {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
supportFragmentManager
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings, LockFragment())
|
||||
.addToBackStack("Lock")
|
||||
.commitAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
else -> super.onActivityResult(requestCode, resultCode, data)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,11 @@ package xyz.quaver.pupil.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import androidx.core.content.ContextCompat
|
||||
import kotlinx.serialization.*
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonConfiguration
|
||||
import java.io.File
|
||||
import java.security.MessageDigest
|
||||
|
||||
fun hash(password: String): String {
|
||||
@@ -21,10 +26,20 @@ fun hashWithSalt(password: String): Pair<String, String> {
|
||||
|
||||
val source = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
|
||||
data class Lock(private val type: Type, private val hash: String, private val salt: String) {
|
||||
@Serializable
|
||||
data class Lock(val type: Type, val hash: String, val salt: String) {
|
||||
|
||||
enum class Type {
|
||||
PATTERN
|
||||
PATTERN,
|
||||
PIN,
|
||||
PASSWORD
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun generate(type: Type, password: String): Lock {
|
||||
val (hash, salt) = hashWithSalt(password)
|
||||
return Lock(type, hash, salt)
|
||||
}
|
||||
}
|
||||
|
||||
fun match(password: String): Boolean {
|
||||
@@ -34,6 +49,57 @@ data class Lock(private val type: Type, private val hash: String, private val sa
|
||||
|
||||
class LockManager(base: Context): ContextWrapper(base) {
|
||||
|
||||
var locks: ArrayList<Lock>? = null
|
||||
|
||||
init {
|
||||
load()
|
||||
}
|
||||
|
||||
@UseExperimental(ImplicitReflectionSerializer::class)
|
||||
private fun load() {
|
||||
val lock = File(ContextCompat.getDataDir(this), "lock.json")
|
||||
|
||||
if (!lock.exists()) {
|
||||
lock.createNewFile()
|
||||
lock.writeText("[]")
|
||||
}
|
||||
|
||||
locks = ArrayList(Json(JsonConfiguration.Stable).parseList(lock.readText()))
|
||||
}
|
||||
|
||||
@UseExperimental(ImplicitReflectionSerializer::class)
|
||||
private fun save() {
|
||||
val lock = File(ContextCompat.getDataDir(this), "lock.json")
|
||||
|
||||
if (!lock.exists())
|
||||
lock.createNewFile()
|
||||
|
||||
lock.writeText(Json(JsonConfiguration.Stable).stringify(locks?.toList() ?: listOf()))
|
||||
}
|
||||
|
||||
fun add(lock: Lock) {
|
||||
remove(lock.type)
|
||||
locks?.add(lock)
|
||||
save()
|
||||
}
|
||||
|
||||
fun remove(type: Lock.Type) {
|
||||
locks?.removeAll { it.type == type }
|
||||
save()
|
||||
}
|
||||
|
||||
fun check(password: String): Boolean? {
|
||||
return locks?.any {
|
||||
it.match(password)
|
||||
}
|
||||
}
|
||||
|
||||
fun empty(): Boolean {
|
||||
return locks.isNullOrEmpty()
|
||||
}
|
||||
|
||||
fun contains(type: Lock.Type): Boolean {
|
||||
return locks?.any { it.type == type } ?: false
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,6 +31,16 @@
|
||||
app:backgroundTint="@color/colorPrimary"
|
||||
app:fabSize="mini"/>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/lock_pin"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/numeric"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
app:backgroundTint="@color/dark_gray"
|
||||
app:fabSize="mini"/>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/lock_fingerprint"
|
||||
android:layout_width="wrap_content"
|
||||
|
||||
@@ -70,4 +70,13 @@
|
||||
<string name="settings_app_lock">アプリロック</string>
|
||||
<string name="settings_app_lock_type">アップロックの種類</string>
|
||||
<string name="settings_app_version_title">バージョン</string>
|
||||
<string name="settings_lock_biomatrics">生体認識</string>
|
||||
<string name="settings_lock_confirm">ロック確認のためもう一回入力してください。</string>
|
||||
<string name="settings_lock_enabled">有効</string>
|
||||
<string name="settings_lock_fingerprint">指紋</string>
|
||||
<string name="settings_lock_password">パスワード</string>
|
||||
<string name="settings_lock_pattern">パターン</string>
|
||||
<string name="settings_lock_wrong_confirm">ロックが一致しません。やり直してください。</string>
|
||||
<string name="settings_lock_none">なし</string>
|
||||
<string name="settings_lock_remove_message">ロックを無効にしますか?</string>
|
||||
</resources>
|
||||
@@ -70,4 +70,13 @@
|
||||
<string name="settings_app_lock">앱 잠금</string>
|
||||
<string name="settings_app_lock_type">앱 잠금 종류</string>
|
||||
<string name="settings_app_version_title">앱 버전</string>
|
||||
<string name="settings_lock_biomatrics">생체 인식</string>
|
||||
<string name="settings_lock_confirm">잠금 확인을 위해 한번 더 입력해주세요</string>
|
||||
<string name="settings_lock_enabled">사용 중</string>
|
||||
<string name="settings_lock_fingerprint">지문</string>
|
||||
<string name="settings_lock_password">비밀번호</string>
|
||||
<string name="settings_lock_pattern">패턴</string>
|
||||
<string name="settings_lock_wrong_confirm">잠금이 일치하지 않습니다. 다시 시도하세요.</string>
|
||||
<string name="settings_lock_none">없음</string>
|
||||
<string name="settings_lock_remove_message">잠금을 해제할까요?</string>
|
||||
</resources>
|
||||
@@ -101,6 +101,17 @@
|
||||
<string name="settings_security_mode_title">Enable security mode</string>
|
||||
<string name="settings_security_mode_summary">Enable security mode to make the screen invisible on recent app window</string>
|
||||
|
||||
<string name="settings_lock_none">None</string>
|
||||
<string name="settings_lock_pattern">Pattern</string>
|
||||
<string name="settings_lock_pin" translatable="false">PIN</string>
|
||||
<string name="settings_lock_password">Password</string>
|
||||
<string name="settings_lock_biomatrics">Biomatrics</string>
|
||||
<string name="settings_lock_fingerprint">Fingerprint</string>
|
||||
<string name="settings_lock_enabled">Enabled</string>
|
||||
<string name="settings_lock_confirm">Input same lock once more to confirm Lock</string>
|
||||
<string name="settings_lock_remove_message">Do you want to remove lock?</string>
|
||||
<string name="settings_lock_wrong_confirm">Lock is different from last one. Please try again.</string>
|
||||
|
||||
<string name="default_query_dialog_title">Set default query</string>
|
||||
<string name="default_query_dialog_language">Language: </string>
|
||||
<string name="default_query_dialog_filter_BL">Filter BL</string>
|
||||
|
||||
26
app/src/main/res/xml/lock_preferences.xml
Normal file
26
app/src/main/res/xml/lock_preferences.xml
Normal file
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.preference.PreferenceScreen
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<Preference
|
||||
app:title="@string/settings_lock_pattern"
|
||||
app:key="lock_pattern"/>
|
||||
|
||||
<Preference
|
||||
app:title="@string/settings_lock_pin"
|
||||
app:key="lock_pin"/>
|
||||
|
||||
<Preference
|
||||
app:title="@string/settings_lock_password"
|
||||
app:key="lock_password"/>
|
||||
|
||||
<PreferenceCategory
|
||||
app:title="@string/settings_lock_biomatrics">
|
||||
|
||||
<Preference
|
||||
app:title="@string/settings_lock_fingerprint"
|
||||
app:key="lock_fingerprint"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</androidx.preference.PreferenceScreen>
|
||||
Reference in New Issue
Block a user