Add option to disable auto lock and add manual locking

This commit is contained in:
NerdNumber9 2018-03-14 18:39:01 -04:00
parent 0dd9e9e015
commit c48bebe0b2
11 changed files with 102 additions and 26 deletions

View File

@ -15,6 +15,8 @@
<uses-permission android:name="android.permission.GET_TASKS"/> <uses-permission android:name="android.permission.GET_TASKS"/>
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" /> tools:ignore="ProtectedPermissions" />
<!-- Lock vibrate -->
<uses-permission android:name="android.permission.VIBRATE"/>
<application <application
android:name=".App" android:name=".App"

View File

@ -121,6 +121,16 @@ object PreferenceKeys {
fun trackToken(syncId: Int) = "track_token_$syncId" fun trackToken(syncId: Int) = "track_token_$syncId"
const val eh_lock_hash = "lock_hash"
const val eh_lock_salt = "lock_salt"
const val eh_lock_length = "lock_length"
const val eh_lock_finger = "lock_finger"
const val eh_lock_manually = "eh_lock_manually"
const val eh_nh_useHighQualityThumbs = "eh_nh_hq_thumbs" const val eh_nh_useHighQualityThumbs = "eh_nh_hq_thumbs"
const val eh_showSyncIntro = "eh_show_sync_intro" const val eh_showSyncIntro = "eh_show_sync_intro"

View File

@ -203,13 +203,15 @@ class PreferencesHelper(val context: Context) {
fun eh_sessionCookie() = rxPrefs.getString(Keys.eh_sessionCookie, "") fun eh_sessionCookie() = rxPrefs.getString(Keys.eh_sessionCookie, "")
//Lock //Lock
fun lockHash() = rxPrefs.getString("lock_hash", null) fun eh_lockHash() = rxPrefs.getString(Keys.eh_lock_hash, null)
fun lockSalt() = rxPrefs.getString("lock_salt", null) fun eh_lockSalt() = rxPrefs.getString(Keys.eh_lock_salt, null)
fun lockLength() = rxPrefs.getInteger("lock_length", -1) fun eh_lockLength() = rxPrefs.getInteger(Keys.eh_lock_length, -1)
fun lockUseFingerprint() = rxPrefs.getBoolean("lock_finger", false) fun eh_lockUseFingerprint() = rxPrefs.getBoolean(Keys.eh_lock_finger, false)
fun eh_lockManually() = rxPrefs.getBoolean(Keys.eh_lock_manually, false)
fun eh_nh_useHighQualityThumbs() = rxPrefs.getBoolean(Keys.eh_nh_useHighQualityThumbs, false) fun eh_nh_useHighQualityThumbs() = rxPrefs.getBoolean(Keys.eh_nh_useHighQualityThumbs, false)

View File

@ -12,8 +12,10 @@ import android.os.Bundle
import android.support.v4.view.GravityCompat import android.support.v4.view.GravityCompat
import android.support.v4.widget.DrawerLayout import android.support.v4.widget.DrawerLayout
import android.support.v7.graphics.drawable.DrawerArrowDrawable import android.support.v7.graphics.drawable.DrawerArrowDrawable
import android.support.v7.widget.Toolbar
import android.view.ViewGroup import android.view.ViewGroup
import com.bluelinelabs.conductor.* import com.bluelinelabs.conductor.*
import com.jakewharton.rxbinding.support.v7.widget.navigationClicks
import eu.kanade.tachiyomi.Migrations import eu.kanade.tachiyomi.Migrations
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
@ -39,6 +41,11 @@ import exh.ui.migration.MetadataFetchDialog
import exh.util.defRealm import exh.util.defRealm
import kotlinx.android.synthetic.main.main_activity.* import kotlinx.android.synthetic.main.main_activity.*
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import android.view.View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION
import android.text.TextUtils
import android.view.View
import com.jakewharton.rxbinding.view.longClicks
import eu.kanade.tachiyomi.util.vibrate
class MainActivity : BaseActivity() { class MainActivity : BaseActivity() {
@ -144,18 +151,26 @@ class MainActivity : BaseActivity() {
}) })
// --> EH
//Hook long press hamburger menu to lock
getToolbarNavigationIcon(toolbar)?.setOnLongClickListener {
doLock(true)
vibrate(50) // Notify user of lock
true
}
//Show lock //Show lock
if (savedInstanceState == null) { if (savedInstanceState == null) {
val lockEnabled = lockEnabled(preferences) val lockEnabled = lockEnabled(preferences)
if (lockEnabled) { if (lockEnabled) {
//Special case first lock //Special case first lock
toolbar.navigationIcon = null
doLock() doLock()
//Check lock security //Check lock security
notifyLockSecurity(this) notifyLockSecurity(this)
} }
} }
// <-- EH
syncActivityViewWithController(router.backstack.lastOrNull()?.controller()) syncActivityViewWithController(router.backstack.lastOrNull()?.controller())
@ -233,6 +248,26 @@ class MainActivity : BaseActivity() {
router.setRoot(controller.withFadeTransaction().tag(id.toString())) router.setRoot(controller.withFadeTransaction().tag(id.toString()))
} }
fun getToolbarNavigationIcon(toolbar: Toolbar): View? {
//check if contentDescription previously was set
val hadContentDescription = TextUtils.isEmpty(toolbar.navigationContentDescription)
val contentDescription = if (!hadContentDescription) toolbar.navigationContentDescription else "navigationIcon"
toolbar.navigationContentDescription = contentDescription
val potentialViews = ArrayList<View>()
//find the view based on it's content description, set programmatically or with android:contentDescription
toolbar.findViewsWithText(potentialViews, contentDescription, View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION)
//Nav icon is always instantiated at this point because calling setNavigationContentDescription ensures its existence
val navIcon = potentialViews.firstOrNull()
//Clear content description if not previously present
if (hadContentDescription)
toolbar.navigationContentDescription = null
return navIcon
}
private fun syncActivityViewWithController(to: Controller?, from: Controller? = null) { private fun syncActivityViewWithController(to: Controller?, from: Controller? = null) {
if (from is DialogController || to is DialogController) { if (from is DialogController || to is DialogController) {
return return
@ -249,6 +284,7 @@ class MainActivity : BaseActivity() {
//Special case and hide drawer arrow for lock controller //Special case and hide drawer arrow for lock controller
if(to is LockController) { if(to is LockController) {
supportActionBar?.setDisplayHomeAsUpEnabled(false) supportActionBar?.setDisplayHomeAsUpEnabled(false)
toolbar.navigationIcon = null
} else { } else {
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
toolbar.navigationIcon = drawerArrow toolbar.navigationIcon = drawerArrow
@ -308,6 +344,10 @@ class MainActivity : BaseActivity() {
if(router.backstack.lastOrNull()?.controller() is LockController) if(router.backstack.lastOrNull()?.controller() is LockController)
return return
//Do not lock if manual lock enabled
if(preferences.eh_lockManually().getOrDefault())
return
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
val mUsageStatsManager = getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager val mUsageStatsManager = getSystemService(Context.USAGE_STATS_SERVICE) as UsageStatsManager
val time = System.currentTimeMillis() val time = System.currentTimeMillis()
@ -331,9 +371,9 @@ class MainActivity : BaseActivity() {
} }
} }
fun doLock() { fun doLock(animate: Boolean = false) {
router.pushController(RouterTransaction.with(LockController()) router.pushController(RouterTransaction.with(LockController())
.popChangeHandler(LockChangeHandler())) .popChangeHandler(LockChangeHandler(animate)))
} }
// <-- EH // <-- EH

View File

@ -4,7 +4,6 @@ import android.app.Dialog
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.support.v7.preference.PreferenceScreen import android.support.v7.preference.PreferenceScreen
import android.support.v7.preference.SwitchPreference
import android.view.View import android.view.View
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
@ -197,6 +196,14 @@ class SettingsGeneralController : SettingsController() {
//Call after addPreference //Call after addPreference
dependency = "pref_app_lock" dependency = "pref_app_lock"
} }
switchPreference {
key = Keys.eh_lock_manually
title = "Lock manually only"
summary = "Disable automatic app locking. The app can still be locked manually by long-pressing the three-lines/back button in the top left corner."
defaultValue = false
}
} }
} }

View File

@ -5,13 +5,17 @@ import android.app.Notification
import android.app.NotificationManager import android.app.NotificationManager
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Context.VIBRATOR_SERVICE
import android.content.Intent import android.content.Intent
import android.content.IntentFilter import android.content.IntentFilter
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Resources import android.content.res.Resources
import android.net.ConnectivityManager import android.net.ConnectivityManager
import android.net.wifi.WifiManager import android.net.wifi.WifiManager
import android.os.Build
import android.os.PowerManager import android.os.PowerManager
import android.os.VibrationEffect
import android.os.Vibrator
import android.support.annotation.StringRes import android.support.annotation.StringRes
import android.support.v4.app.NotificationCompat import android.support.v4.app.NotificationCompat
import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat
@ -20,6 +24,8 @@ import android.widget.Toast
import com.nononsenseapps.filepicker.FilePickerActivity import com.nononsenseapps.filepicker.FilePickerActivity
import eu.kanade.tachiyomi.widget.CustomLayoutPickerActivity import eu.kanade.tachiyomi.widget.CustomLayoutPickerActivity
/** /**
* Display a toast in this context. * Display a toast in this context.
* *
@ -168,4 +174,13 @@ fun Context.isServiceRunning(serviceClass: Class<*>): Boolean {
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
return manager.getRunningServices(Integer.MAX_VALUE) return manager.getRunningServices(Integer.MAX_VALUE)
.any { className == it.service.className } .any { className == it.service.className }
}
fun Context.vibrate(time: Long) {
val vibeService = getSystemService(VIBRATOR_SERVICE) as Vibrator
if (Build.VERSION.SDK_INT >= 26) {
vibeService.vibrate(VibrationEffect.createOneShot(time, VibrationEffect.DEFAULT_AMPLITUDE))
} else {
vibeService.vibrate(time)
}
} }

View File

@ -34,7 +34,7 @@ class FingerLockPreference @JvmOverloads constructor(context: Context, attrs: At
val useFingerprint val useFingerprint
get() = fingerprintSupported get() = fingerprintSupported
&& prefs.lockUseFingerprint().getOrDefault() && prefs.eh_lockUseFingerprint().getOrDefault()
@SuppressLint("NewApi") @SuppressLint("NewApi")
override fun onAttached() { override fun onAttached() {
@ -45,7 +45,7 @@ class FingerLockPreference @JvmOverloads constructor(context: Context, attrs: At
if(it as Boolean) if(it as Boolean)
tryChange() tryChange()
else else
prefs.lockUseFingerprint().set(false) prefs.eh_lockUseFingerprint().set(false)
!it !it
} }
} else { } else {
@ -121,7 +121,7 @@ class FingerLockPreference @JvmOverloads constructor(context: Context, attrs: At
when (result.status) { when (result.status) {
AuthenticationResult.Status.SUCCESS -> { AuthenticationResult.Status.SUCCESS -> {
iconView.setState(SwirlView.State.ON) iconView.setState(SwirlView.State.ON)
prefs.lockUseFingerprint().set(true) prefs.eh_lockUseFingerprint().set(true)
dialog.dismiss() dialog.dismiss()
updateSummary() updateSummary()
} }

View File

@ -41,12 +41,12 @@ class LockController : NucleusController<LockPresenter>() {
//Setup pin lock //Setup pin lock
pin_lock_view.attachIndicatorDots(indicator_dots) pin_lock_view.attachIndicatorDots(indicator_dots)
pin_lock_view.pinLength = prefs.lockLength().getOrDefault() pin_lock_view.pinLength = prefs.eh_lockLength().getOrDefault()
pin_lock_view.setPinLockListener(object : PinLockListener { pin_lock_view.setPinLockListener(object : PinLockListener {
override fun onEmpty() {} override fun onEmpty() {}
override fun onComplete(pin: String) { override fun onComplete(pin: String) {
if (sha512(pin, prefs.lockSalt().get()!!) == prefs.lockHash().get()) { if (sha512(pin, prefs.eh_lockSalt().get()!!) == prefs.eh_lockHash().get()) {
//Yay! //Yay!
closeLock() closeLock()
} else { } else {
@ -120,7 +120,7 @@ class LockController : NucleusController<LockPresenter>() {
private fun resolvColor(color: Int): Int { private fun resolvColor(color: Int): Int {
val typedVal = TypedValue() val typedVal = TypedValue()
activity!!.theme!!.resolveAttribute(android.R.attr.windowBackground, typedVal, true) activity!!.theme!!.resolveAttribute(color, typedVal, true)
return typedVal.data return typedVal.data
} }

View File

@ -1,8 +1,6 @@
package exh.ui.lock package exh.ui.lock
import android.content.Context import android.content.Context
import android.support.v7.preference.Preference
import android.support.v7.preference.SwitchPreference
import android.support.v7.preference.SwitchPreferenceCompat import android.support.v7.preference.SwitchPreferenceCompat
import android.text.InputType import android.text.InputType
import android.util.AttributeSet import android.util.AttributeSet
@ -87,8 +85,8 @@ class LockPreference @JvmOverloads constructor(context: Context, attrs: Attribut
hash = sha512(password, salt) hash = sha512(password, salt)
length = password.length length = password.length
} }
prefs.lockSalt().set(salt) prefs.eh_lockSalt().set(salt)
prefs.lockHash().set(hash) prefs.eh_lockHash().set(hash)
prefs.lockLength().set(length) prefs.eh_lockLength().set(length)
} }
} }

View File

@ -14,6 +14,6 @@ class LockPresenter: BasePresenter<LockController>() {
get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& Reprint.isHardwarePresent() && Reprint.isHardwarePresent()
&& Reprint.hasFingerprintRegistered() && Reprint.hasFingerprintRegistered()
&& prefs.lockUseFingerprint().getOrDefault() && prefs.eh_lockUseFingerprint().getOrDefault()
} }

View File

@ -1,7 +1,6 @@
package exh.ui.lock package exh.ui.lock
import android.annotation.TargetApi import android.annotation.TargetApi
import android.app.Activity
import android.app.AppOpsManager import android.app.AppOpsManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@ -40,17 +39,20 @@ fun sha512(passwordToHash: String, salt: String): String {
* Check if lock is enabled * Check if lock is enabled
*/ */
fun lockEnabled(prefs: PreferencesHelper = Injekt.get()) fun lockEnabled(prefs: PreferencesHelper = Injekt.get())
= prefs.lockHash().get() != null = prefs.eh_lockHash().get() != null
&& prefs.lockSalt().get() != null && prefs.eh_lockSalt().get() != null
&& prefs.lockLength().getOrDefault() != -1 && prefs.eh_lockLength().getOrDefault() != -1
/** /**
* Check if the lock will function properly * Check if the lock will function properly
* *
* @return true if action is required, false if lock is working properly * @return true if action is required, false if lock is working properly
*/ */
fun notifyLockSecurity(context: Context): Boolean { fun notifyLockSecurity(context: Context,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !hasAccessToUsageStats(context)) { prefs: PreferencesHelper = Injekt.get()): Boolean {
if (!prefs.eh_lockManually().getOrDefault()
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
&& !hasAccessToUsageStats(context)) {
MaterialDialog.Builder(context) MaterialDialog.Builder(context)
.title("Permission required") .title("Permission required")
.content("${context.getString(R.string.app_name)} requires the usage stats permission to detect when you leave the app. " + .content("${context.getString(R.string.app_name)} requires the usage stats permission to detect when you leave the app. " +