mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-05 19:42:20 +02:00
Improve experience at android tv
This commit is contained in:
parent
0134dc5e0e
commit
494a82745c
22 changed files with 403 additions and 79 deletions
|
@ -32,9 +32,13 @@
|
|||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.CALL_PHONE" />
|
||||
|
||||
<uses-feature android:name="android.hardware.telephony" android:required="false" />
|
||||
<uses-feature android:name="android.software.leanback" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
|
||||
|
||||
<application
|
||||
android:banner="@drawable/banner"
|
||||
android:name=".Application"
|
||||
android:allowBackup="false"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
|
@ -51,8 +55,8 @@
|
|||
android:name=".ui.MainActivity">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||
*
|
||||
* 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
|
||||
|
@ -20,7 +20,9 @@ import android.app.AppOpsManager
|
|||
import android.app.usage.UsageEvents
|
||||
import android.app.usage.UsageStatsManager
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import io.timelimit.android.BuildConfig
|
||||
import io.timelimit.android.coroutines.executeAndWait
|
||||
import io.timelimit.android.integration.platform.ForegroundAppSpec
|
||||
import io.timelimit.android.integration.platform.RuntimePermissionStatus
|
||||
|
@ -35,6 +37,7 @@ class LollipopForegroundAppHelper(private val context: Context) : ForegroundAppH
|
|||
|
||||
private val usageStatsManager = context.getSystemService(if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) Context.USAGE_STATS_SERVICE else "usagestats") as UsageStatsManager
|
||||
private val appOpsManager = context.getSystemService(Context.APP_OPS_SERVICE) as AppOpsManager
|
||||
private val packageManager = context.packageManager
|
||||
|
||||
private var lastQueryTime: Long = 0
|
||||
private var lastPackage: String? = null
|
||||
|
@ -94,8 +97,13 @@ class LollipopForegroundAppHelper(private val context: Context) : ForegroundAppH
|
|||
}
|
||||
|
||||
override fun getPermissionStatus(): RuntimePermissionStatus {
|
||||
if(appOpsManager.checkOpNoThrow("android:get_usage_stats",
|
||||
android.os.Process.myUid(), context.packageName) == AppOpsManager.MODE_ALLOWED) {
|
||||
val appOpsStatus = appOpsManager.checkOpNoThrow("android:get_usage_stats", android.os.Process.myUid(), context.packageName)
|
||||
val packageManagerStatus = packageManager.checkPermission("android.permission.PACKAGE_USAGE_STATS", BuildConfig.APPLICATION_ID)
|
||||
|
||||
val allowedUsingSystemSettings = appOpsStatus == AppOpsManager.MODE_ALLOWED
|
||||
val allowedUsingAdb = appOpsStatus == AppOpsManager.MODE_DEFAULT && packageManagerStatus == PackageManager.PERMISSION_GRANTED
|
||||
|
||||
if(allowedUsingSystemSettings || allowedUsingAdb) {
|
||||
return RuntimePermissionStatus.Granted
|
||||
} else {
|
||||
return RuntimePermissionStatus.NotGranted
|
||||
|
|
|
@ -126,11 +126,15 @@ class ContactsFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun showContactSelection() {
|
||||
startActivityForResult(
|
||||
Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)
|
||||
.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE),
|
||||
REQ_SELECT_CONTACT
|
||||
)
|
||||
try {
|
||||
startActivityForResult(
|
||||
Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI)
|
||||
.setType(ContactsContract.CommonDataKinds.Phone.CONTENT_TYPE),
|
||||
REQ_SELECT_CONTACT
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
Snackbar.make(view!!, R.string.error_general, Snackbar.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeItem(item: AllowedContact) {
|
||||
|
|
|
@ -30,6 +30,7 @@ import androidx.lifecycle.ViewModelProviders
|
|||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import io.timelimit.android.R
|
||||
import io.timelimit.android.async.Threads
|
||||
import io.timelimit.android.data.model.User
|
||||
import io.timelimit.android.databinding.NewLoginFragmentBinding
|
||||
import io.timelimit.android.extensions.setOnEnterListenr
|
||||
|
@ -168,7 +169,7 @@ class NewLoginFragment: DialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
model.status.observe(this, Observer { status ->
|
||||
model.status.observe(viewLifecycleOwner, Observer { status ->
|
||||
when (status) {
|
||||
LoginDialogDone -> {
|
||||
dismissAllowingStateLoss()
|
||||
|
@ -181,6 +182,10 @@ class NewLoginFragment: DialogFragment() {
|
|||
}
|
||||
|
||||
adapter.data = status.usersToShow
|
||||
|
||||
Threads.mainThreadHandler.post { binding.userList.recycler.requestFocus() }
|
||||
|
||||
null
|
||||
}
|
||||
is ParentUserLogin -> {
|
||||
if (binding.switcher.displayedChild != PARENT_AUTH) {
|
||||
|
@ -189,6 +194,8 @@ class NewLoginFragment: DialogFragment() {
|
|||
binding.switcher.displayedChild = PARENT_AUTH
|
||||
}
|
||||
|
||||
binding.enterPassword.password.isEnabled = !status.isCheckingPassword
|
||||
|
||||
if (!binding.enterPassword.showCustomKeyboard) {
|
||||
binding.enterPassword.password.requestFocus()
|
||||
inputMethodManager.showSoftInput(binding.enterPassword.password, 0)
|
||||
|
@ -213,8 +220,6 @@ class NewLoginFragment: DialogFragment() {
|
|||
binding.enterPassword.checkAssignMyself.setOnCheckedChangeListener { _, _ -> bindCanNotKeepLoggedIn() }
|
||||
}
|
||||
|
||||
binding.enterPassword.password.isEnabled = !status.isCheckingPassword
|
||||
|
||||
if (status.wasPasswordWrong) {
|
||||
Toast.makeText(context!!, R.string.login_snackbar_wrong, Toast.LENGTH_SHORT).show()
|
||||
binding.enterPassword.password.setText("")
|
||||
|
|
|
@ -52,7 +52,7 @@ object AuthenticationFab {
|
|||
val highlightObserver = Observer<Boolean> {
|
||||
if (it == true) {
|
||||
if (tapTargetView == null && fab.isAttachedToWindow) {
|
||||
tapTargetView = TapTargetView.showFor(fragment.activity!!,
|
||||
tapTargetView = MyTapTargetView.showFor(fragment.activity!!,
|
||||
TapTarget.forView(fab, fragment.getString(R.string.authentication_required_overlay_title), fragment.getString(R.string.authentication_required_overlay_text))
|
||||
.cancelable(true)
|
||||
.tintTarget(true)
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||
*
|
||||
* 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 version 3 of the License.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package io.timelimit.android.ui.main
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewManager
|
||||
import com.getkeepsafe.taptargetview.TapTarget
|
||||
import com.getkeepsafe.taptargetview.TapTargetView
|
||||
|
||||
@SuppressLint("ViewConstructor")
|
||||
class MyTapTargetView(
|
||||
context: Context, parent: ViewManager, boundingParent: ViewGroup?, target: TapTarget?, val userListener: Listener?
|
||||
): TapTargetView(context, parent, boundingParent, target, userListener) {
|
||||
companion object {
|
||||
fun showFor(activity: Activity, target: TapTarget?, listener: Listener?): TapTargetView? {
|
||||
val decor = activity.window.decorView as ViewGroup
|
||||
val layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)
|
||||
val content = decor.findViewById<View>(android.R.id.content) as ViewGroup
|
||||
val tapTargetView = MyTapTargetView(activity, decor, content, target, listener)
|
||||
|
||||
decor.addView(tapTargetView, layoutParams)
|
||||
|
||||
return tapTargetView
|
||||
}
|
||||
}
|
||||
|
||||
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
|
||||
if (isVisible && (
|
||||
keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER)
|
||||
) {
|
||||
userListener?.onTargetClick(this)
|
||||
|
||||
return true
|
||||
} else {
|
||||
return super.onKeyDown(keyCode, event)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||
*
|
||||
* 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 version 3 of the License.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package io.timelimit.android.ui.manage.device.manage.permission
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import io.timelimit.android.BuildConfig
|
||||
import io.timelimit.android.R
|
||||
import io.timelimit.android.extensions.showSafe
|
||||
import io.timelimit.android.integration.platform.android.AdminReceiver
|
||||
|
||||
class AdbDeviceAdminDialogFragment: DialogFragment() {
|
||||
companion object {
|
||||
private const val DIALOG_TAG = "AdbDeviceAdminDialogFragment"
|
||||
private val GRANT_COMMAND = "adb shell dpm set-active-admin --user current ${BuildConfig.APPLICATION_ID}/${AdminReceiver::class.java.canonicalName}"
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = AlertDialog.Builder(context!!, theme)
|
||||
.setTitle(R.string.manage_device_permission_device_admin_title)
|
||||
.setMessage(getString(R.string.manage_device_permission_no_ui_device_admin, GRANT_COMMAND))
|
||||
.setPositiveButton(R.string.generic_ok, null)
|
||||
.create()
|
||||
|
||||
fun show(fragmentManager: FragmentManager) = showSafe(fragmentManager, DIALOG_TAG)
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||
*
|
||||
* 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 version 3 of the License.
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package io.timelimit.android.ui.manage.device.manage.permission
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import io.timelimit.android.BuildConfig
|
||||
import io.timelimit.android.R
|
||||
import io.timelimit.android.extensions.showSafe
|
||||
|
||||
class AdbUsageStatsDialogFragment: DialogFragment() {
|
||||
companion object {
|
||||
private const val DIALOG_TAG = "AdbUsageStatsDialogFragment"
|
||||
private const val PERMISSION = "android.permission.PACKAGE_USAGE_STATS"
|
||||
private const val GRANT_COMMAND = "adb shell pm grant ${BuildConfig.APPLICATION_ID} $PERMISSION"
|
||||
private const val REVOKE_COMMAND = "adb shell pm revoke ${BuildConfig.APPLICATION_ID} $PERMISSION"
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = AlertDialog.Builder(context!!, theme)
|
||||
.setTitle(R.string.manage_device_permissions_usagestats_title)
|
||||
.setMessage(getString(R.string.manage_device_permission_no_ui_usage_stats_text, GRANT_COMMAND, REVOKE_COMMAND))
|
||||
.setPositiveButton(R.string.generic_ok, null)
|
||||
.create()
|
||||
|
||||
fun show(fragmentManager: FragmentManager) = showSafe(fragmentManager, DIALOG_TAG)
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||
*
|
||||
* 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
|
||||
|
@ -41,13 +41,17 @@ class InformAboutDeviceOwnerDialogFragment: DialogFragment() {
|
|||
.setTitle(R.string.inform_about_device_owner_title)
|
||||
.setMessage(R.string.inform_about_device_owner_text)
|
||||
.setPositiveButton(R.string.inform_about_device_owner_continue) { _, _ ->
|
||||
startActivity(
|
||||
Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
|
||||
.putExtra(
|
||||
DevicePolicyManager.EXTRA_DEVICE_ADMIN,
|
||||
ComponentName(context!!, AdminReceiver::class.java)
|
||||
)
|
||||
)
|
||||
try {
|
||||
startActivity(
|
||||
Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
|
||||
.putExtra(
|
||||
DevicePolicyManager.EXTRA_DEVICE_ADMIN,
|
||||
ComponentName(context!!, AdminReceiver::class.java)
|
||||
)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
AdbDeviceAdminDialogFragment().show(parentFragmentManager)
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.generic_cancel, null)
|
||||
.create()
|
||||
|
|
|
@ -126,10 +126,14 @@ class ManageDevicePermissionsFragment : Fragment(), FragmentWithCustomTitle {
|
|||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
try {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
AdbUsageStatsDialogFragment().show(parentFragmentManager)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,28 +147,32 @@ class ManageDevicePermissionsFragment : Fragment(), FragmentWithCustomTitle {
|
|||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
R.string.error_general,
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
Toast.makeText(context, R.string.error_general, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun openDrawOverOtherAppsScreen() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context!!.packageName))
|
||||
)
|
||||
try {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context!!.packageName))
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
Toast.makeText(context, R.string.error_general, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun openAccessibilitySettings() {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
try {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
Toast.makeText(context, R.string.error_general, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun manageDeviceAdmin() {
|
||||
|
@ -175,19 +183,27 @@ class ManageDevicePermissionsFragment : Fragment(), FragmentWithCustomTitle {
|
|||
if (InformAboutDeviceOwnerDialogFragment.shouldShow) {
|
||||
InformAboutDeviceOwnerDialogFragment().show(fragmentManager!!)
|
||||
} else {
|
||||
startActivity(
|
||||
Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
|
||||
.putExtra(
|
||||
DevicePolicyManager.EXTRA_DEVICE_ADMIN,
|
||||
ComponentName(context!!, AdminReceiver::class.java)
|
||||
)
|
||||
)
|
||||
try {
|
||||
startActivity(
|
||||
Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
|
||||
.putExtra(
|
||||
DevicePolicyManager.EXTRA_DEVICE_ADMIN,
|
||||
ComponentName(context!!, AdminReceiver::class.java)
|
||||
)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
AdbDeviceAdminDialogFragment().show(parentFragmentManager)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_SECURITY_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
try {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_SECURITY_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
AdbDeviceAdminDialogFragment().show(parentFragmentManager)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import android.widget.Toast
|
|||
import androidx.fragment.app.Fragment
|
||||
import androidx.navigation.Navigation
|
||||
import io.timelimit.android.R
|
||||
import io.timelimit.android.async.Threads
|
||||
import io.timelimit.android.databinding.FragmentSetupDevicePermissionsBinding
|
||||
import io.timelimit.android.extensions.safeNavigate
|
||||
import io.timelimit.android.integration.platform.ProtectionLevel
|
||||
|
@ -36,6 +37,8 @@ import io.timelimit.android.integration.platform.android.AdminReceiver
|
|||
import io.timelimit.android.logic.AppLogic
|
||||
import io.timelimit.android.logic.DefaultAppLogic
|
||||
import io.timelimit.android.ui.help.HelpDialogFragment
|
||||
import io.timelimit.android.ui.manage.device.manage.permission.AdbDeviceAdminDialogFragment
|
||||
import io.timelimit.android.ui.manage.device.manage.permission.AdbUsageStatsDialogFragment
|
||||
import io.timelimit.android.ui.manage.device.manage.permission.InformAboutDeviceOwnerDialogFragment
|
||||
|
||||
|
||||
|
@ -43,6 +46,16 @@ class SetupDevicePermissionsFragment : Fragment() {
|
|||
private val logic: AppLogic by lazy { DefaultAppLogic.with(context!!) }
|
||||
private lateinit var binding: FragmentSetupDevicePermissionsBinding
|
||||
|
||||
lateinit var refreshStatusRunnable: Runnable
|
||||
|
||||
init {
|
||||
refreshStatusRunnable = Runnable {
|
||||
refreshStatus()
|
||||
|
||||
Threads.mainThreadHandler.postDelayed(refreshStatusRunnable, 2000L)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
val navigation = Navigation.findNavController(container!!)
|
||||
|
||||
|
@ -56,19 +69,27 @@ class SetupDevicePermissionsFragment : Fragment() {
|
|||
if (InformAboutDeviceOwnerDialogFragment.shouldShow) {
|
||||
InformAboutDeviceOwnerDialogFragment().show(fragmentManager!!)
|
||||
} else {
|
||||
startActivity(
|
||||
Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
|
||||
.putExtra(
|
||||
DevicePolicyManager.EXTRA_DEVICE_ADMIN,
|
||||
ComponentName(context!!, AdminReceiver::class.java)
|
||||
)
|
||||
)
|
||||
try {
|
||||
startActivity(
|
||||
Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN)
|
||||
.putExtra(
|
||||
DevicePolicyManager.EXTRA_DEVICE_ADMIN,
|
||||
ComponentName(context!!, AdminReceiver::class.java)
|
||||
)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
AdbDeviceAdminDialogFragment().show(parentFragmentManager)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_SECURITY_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
try {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_SECURITY_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
AdbDeviceAdminDialogFragment().show(parentFragmentManager)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,10 +108,14 @@ class SetupDevicePermissionsFragment : Fragment() {
|
|||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
try {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
AdbUsageStatsDialogFragment().show(parentFragmentManager)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -112,18 +137,26 @@ class SetupDevicePermissionsFragment : Fragment() {
|
|||
|
||||
override fun openDrawOverOtherAppsScreen() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context!!.packageName))
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
try {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context!!.packageName))
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
Toast.makeText(context, R.string.error_general, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun openAccessibilitySettings() {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
try {
|
||||
startActivity(
|
||||
Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
)
|
||||
} catch (ex: Exception) {
|
||||
Toast.makeText(context, R.string.error_general, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun gotoNextStep() {
|
||||
|
@ -181,7 +214,14 @@ class SetupDevicePermissionsFragment : Fragment() {
|
|||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
refreshStatus()
|
||||
// this additionally schedules it
|
||||
refreshStatusRunnable.run()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
|
||||
Threads.mainThreadHandler.removeCallbacks(refreshStatusRunnable)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||
*
|
||||
* 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
|
||||
|
@ -57,7 +57,12 @@ class SelectCustomServerDialogFragment : BottomSheetDialogFragment() {
|
|||
model.status.observe(this, Observer {
|
||||
when (it!!) {
|
||||
SelectCustomServerStatus.Done -> dismiss()
|
||||
SelectCustomServerStatus.Idle -> binding.isWorking = false
|
||||
SelectCustomServerStatus.Idle -> {
|
||||
binding.isWorking = false
|
||||
binding.executePendingBindings()
|
||||
|
||||
binding.url.requestFocus()
|
||||
}
|
||||
SelectCustomServerStatus.Working -> binding.isWorking = true
|
||||
}
|
||||
})
|
||||
|
|
BIN
app/src/main/res/drawable/banner.png
Normal file
BIN
app/src/main/res/drawable/banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
|
@ -70,6 +70,7 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
<SeekBar
|
||||
android:nextFocusDown="@id/confirm_btn"
|
||||
android:max="10"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
<Switch
|
||||
android:nextFocusDown="@id/extra_time_btn_ok"
|
||||
android:id="@+id/switch_limit_extra_time_to_today"
|
||||
android:text="@string/category_settings_extra_time_switch_limit_to_day"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -75,6 +75,8 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/usage_stats_access_title"
|
||||
android:nextFocusDown="@id/usage_stats_access_btn"
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:drawableTint="?colorOnSurface"
|
||||
android:background="?selectableItemBackground"
|
||||
|
@ -116,6 +118,9 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/usage_stats_access_btn"
|
||||
android:nextFocusUp="@id/usage_stats_access_title"
|
||||
android:nextFocusDown="@id/device_admin_btn"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@string/manage_device_permission_btn_modify"
|
||||
|
@ -123,7 +128,9 @@
|
|||
android:onClick="@{() -> handlers.openUsageStatsSettings()}"
|
||||
android:enabled="@{usageStatsAccess != RuntimePermissionStatus.NotRequired}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content">
|
||||
<requestFocus />
|
||||
</Button>
|
||||
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
@ -173,6 +180,9 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/device_admin_btn"
|
||||
android:nextFocusUp="@id/usage_stats_access_btn"
|
||||
android:nextFocusDown="@id/notification_access_title"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@string/manage_device_permission_btn_modify"
|
||||
|
@ -195,6 +205,9 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notification_access_title"
|
||||
android:nextFocusUp="@id/device_admin_btn"
|
||||
android:nextFocusDown="@id/notification_access_button"
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:drawableTint="?colorOnSurface"
|
||||
android:background="?selectableItemBackground"
|
||||
|
@ -236,6 +249,9 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/notification_access_button"
|
||||
android:nextFocusUp="@id/notification_access_title"
|
||||
android:nextFocusDown="@id/overlay_title"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@string/manage_device_permission_btn_modify"
|
||||
|
@ -259,6 +275,9 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/overlay_title"
|
||||
android:nextFocusUp="@id/notification_access_button"
|
||||
android:nextFocusDown="@id/overlay_btn"
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:drawableTint="?colorOnSurface"
|
||||
android:background="?selectableItemBackground"
|
||||
|
@ -300,6 +319,9 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/overlay_btn"
|
||||
android:nextFocusUp="@id/overlay_title"
|
||||
android:nextFocusDown="@id/accessibility_title"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@string/manage_device_permission_btn_modify"
|
||||
|
@ -323,6 +345,9 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/accessibility_title"
|
||||
android:nextFocusUp="@id/overlay_btn"
|
||||
android:nextFocusDown="@id/accessibility_btn"
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:drawableTint="?colorOnSurface"
|
||||
android:background="?selectableItemBackground"
|
||||
|
@ -354,6 +379,9 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/accessibility_btn"
|
||||
android:nextFocusUp="@id/accessibility_title"
|
||||
android:nextFocusDown="@id/next_btn"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@string/manage_device_permission_btn_modify"
|
||||
|
@ -366,6 +394,8 @@
|
|||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<Button
|
||||
android:nextFocusUp="@id/accessibility_btn"
|
||||
android:id="@+id/next_btn"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
TimeLimit Copyright <C> 2019 Jonas Lochmann
|
||||
TimeLimit Copyright <C> 2019 - 2020 Jonas Lochmann
|
||||
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 version 3 of the License.
|
||||
|
@ -40,6 +40,7 @@
|
|||
android:text="@string/setup_select_mode_intro" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:focusable="true"
|
||||
android:id="@+id/btn_local_mode"
|
||||
android:foreground="?selectableItemBackground"
|
||||
app:cardUseCompatPadding="true"
|
||||
|
@ -64,9 +65,12 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<requestFocus />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:focusable="true"
|
||||
android:visibility="@{BuildConfig.hasServer ? View.VISIBLE : View.GONE}"
|
||||
android:id="@+id/btn_parent_mode"
|
||||
android:foreground="?selectableItemBackground"
|
||||
|
@ -95,6 +99,7 @@
|
|||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:focusable="true"
|
||||
android:visibility="@{BuildConfig.hasServer ? View.VISIBLE : View.GONE}"
|
||||
android:id="@+id/btn_network_child_mode"
|
||||
android:foreground="?selectableItemBackground"
|
||||
|
@ -123,6 +128,7 @@
|
|||
</androidx.cardview.widget.CardView>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:focusable="true"
|
||||
android:id="@+id/btn_uninstall"
|
||||
android:foreground="?selectableItemBackground"
|
||||
app:cardUseCompatPadding="true"
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
|
||||
<Button
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:nextFocusDown="@id/btn_accept"
|
||||
android:id="@+id/custom_server_button"
|
||||
android:text="@string/select_custom_server_button"
|
||||
android:layout_width="wrap_content"
|
||||
|
@ -94,12 +95,15 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<Button
|
||||
android:nextFocusUp="@id/custom_server_button"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_gravity="end"
|
||||
android:id="@+id/btn_accept"
|
||||
android:text="@string/terms_btn_accept"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content">
|
||||
<requestFocus />
|
||||
</Button>
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -116,6 +116,8 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/device_admin_btn"
|
||||
android:nextFocusDown="@id/usage_stats_access_title"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
|
@ -124,7 +126,9 @@
|
|||
android:enabled="@{safeUnbox(isThisDevice)}"
|
||||
android:onClick="@{() -> handlers.manageDeviceAdmin()}"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content">
|
||||
<requestFocus />
|
||||
</Button>
|
||||
|
||||
<TextView
|
||||
android:visibility="@{safeUnbox(isThisDevice) ? View.GONE : View.VISIBLE}"
|
||||
|
@ -147,6 +151,9 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/usage_stats_access_title"
|
||||
android:nextFocusUp="@id/device_admin_btn"
|
||||
android:nextFocusDown="@id/usage_stats_access_btn"
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:drawableTint="?colorOnSurface"
|
||||
android:background="?selectableItemBackground"
|
||||
|
@ -188,6 +195,9 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/usage_stats_access_btn"
|
||||
android:nextFocusUp="@id/usage_stats_access_title"
|
||||
android:nextFocusDown="@id/notification_access_title"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
|
@ -219,6 +229,9 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notification_access_title"
|
||||
android:nextFocusUp="@id/usage_stats_access_btn"
|
||||
android:nextFocusDown="@id/notification_access_button"
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:drawableTint="?colorOnSurface"
|
||||
android:background="?selectableItemBackground"
|
||||
|
@ -260,6 +273,9 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/notification_access_button"
|
||||
android:nextFocusUp="@id/notification_access_title"
|
||||
android:nextFocusDown="@id/overlay_title"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
|
@ -291,6 +307,9 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/overlay_title"
|
||||
android:nextFocusUp="@id/notification_access_button"
|
||||
android:nextFocusDown="@id/overlay_btn"
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:drawableTint="?colorOnSurface"
|
||||
android:background="?selectableItemBackground"
|
||||
|
@ -332,6 +351,9 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/overlay_btn"
|
||||
android:nextFocusUp="@id/overlay_title"
|
||||
android:nextFocusDown="@id/accessibility_title"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
|
@ -363,6 +385,9 @@
|
|||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/accessibility_title"
|
||||
android:nextFocusUp="@id/overlay_btn"
|
||||
android:nextFocusDown="@id/accessibility_btn"
|
||||
tools:ignore="UnusedAttribute"
|
||||
android:drawableTint="?colorOnSurface"
|
||||
android:background="?selectableItemBackground"
|
||||
|
@ -394,6 +419,9 @@
|
|||
android:layout_height="wrap_content" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/accessibility_btn"
|
||||
android:nextFocusUp="@id/accessibility_title"
|
||||
android:nextFocusDown="@id/fab"
|
||||
style="?materialButtonOutlinedStyle"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
|
@ -423,6 +451,7 @@
|
|||
</ScrollView>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:nextFocusUp="@id/accessibility_btn"
|
||||
android:onClick="@{() -> handlers.showAuthenticationScreen()}"
|
||||
android:id="@+id/fab"
|
||||
app:fabSize="normal"
|
||||
|
|
|
@ -45,7 +45,9 @@
|
|||
android:checked="@{safeUnbox(selectedDays.get(0))}"
|
||||
android:text="@string/day_of_week_monday_short"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content">
|
||||
<requestFocus />
|
||||
</com.google.android.material.button.MaterialButton>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
style="?materialButtonOutlinedStyle"
|
||||
|
|
|
@ -108,6 +108,19 @@
|
|||
|
||||
<string name="manage_device_permission_btn_modify">Ändern</string>
|
||||
|
||||
<string name="manage_device_permission_no_ui_usage_stats_text">
|
||||
Dieses Gerät hat keine grafische Oberfläche zum Erteilen dieser Berechtigung - diese kann
|
||||
nur von einem Computer mittels ADB geändert werden.
|
||||
\n\nAktivieren mittels:\n\n%s
|
||||
\n\nDeaktivieren mittels:\n\n%s
|
||||
</string>
|
||||
<string name="manage_device_permission_no_ui_device_admin">
|
||||
Dieses Gerät hat keine grafische Oberfläche zum Erteilen dieser Berechtigung - diese kann
|
||||
nur von einem Computer mittels ADB aktiviert werden:
|
||||
\n\n%s
|
||||
\n\nDie Berechtigung kann über die Deinstallations-Funktion von TimeLimit deaktiviert werden.
|
||||
</string>
|
||||
|
||||
<string name="manage_device_downgrade_title">Downgrade</string>
|
||||
<string name="manage_device_downgrade_text">Auf diesem Gerät wurde eine neuere Version von TimeLimit durch eine ältere ersetzt</string>
|
||||
|
||||
|
|
|
@ -107,6 +107,19 @@
|
|||
|
||||
<string name="manage_device_permission_btn_modify">Modify</string>
|
||||
|
||||
<string name="manage_device_permission_no_ui_usage_stats_text">
|
||||
This device does not allow changing this permission graphically. You can only
|
||||
change it from a PC using ADB.
|
||||
\n\nEnable:\n\n%s
|
||||
\n\nDisable:\n\n%s
|
||||
</string>
|
||||
<string name="manage_device_permission_no_ui_device_admin">
|
||||
This device does not allow changing this permission graphically. You can only
|
||||
enable it from a PC using ADB.
|
||||
\n\n%s
|
||||
\n\nYou can disable it by using the uninstall feature of TimeLimit.
|
||||
</string>
|
||||
|
||||
<string name="manage_device_downgrade_title">Downgrade</string>
|
||||
<string name="manage_device_downgrade_text">On this device, a newer version of TimeLimit was replaced by an older one</string>
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue