mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 01:39:22 +02:00
Compare commits
6 commits
faea667d98
...
e01cf09f51
Author | SHA1 | Date | |
---|---|---|---|
![]() |
e01cf09f51 | ||
![]() |
6e5bee8966 | ||
![]() |
5544883cc3 | ||
![]() |
1d9a1f1071 | ||
![]() |
ac889c142e | ||
![]() |
eb680a4f42 |
21 changed files with 129 additions and 35 deletions
|
@ -30,8 +30,8 @@ android {
|
|||
applicationId "io.timelimit.android"
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 34
|
||||
versionCode 217
|
||||
versionName "7.0.1"
|
||||
versionCode 218
|
||||
versionName "7.1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
kapt {
|
||||
arguments {
|
||||
|
@ -50,6 +50,7 @@ android {
|
|||
buildFeatures {
|
||||
compose true
|
||||
viewBinding true
|
||||
buildConfig true
|
||||
}
|
||||
|
||||
flavorDimensions 'api', 'channel', 'server'
|
||||
|
@ -155,7 +156,7 @@ android {
|
|||
}
|
||||
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.5.5"
|
||||
kotlinCompilerExtensionVersion = "1.5.7"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,21 +168,21 @@ dependencies {
|
|||
def nav_version = "2.5.3"
|
||||
def room_version = "2.6.1"
|
||||
def work_version = '2.9.0'
|
||||
def paging_version = "3.3.0"
|
||||
def paging_version = "3.3.1"
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.21"
|
||||
implementation 'androidx.appcompat:appcompat:1.7.0'
|
||||
implementation 'androidx.core:core:1.13.1'
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
implementation 'androidx.gridlayout:gridlayout:1.0.0'
|
||||
implementation "com.google.android.material:material:1.12.0"
|
||||
implementation 'androidx.compose.material:material:1.6.8'
|
||||
implementation 'androidx.activity:activity-compose:1.9.0'
|
||||
implementation 'androidx.activity:activity-compose:1.9.1'
|
||||
implementation "com.google.accompanist:accompanist-flowlayout:0.30.0"
|
||||
implementation 'androidx.compose.material:material-icons-extended:1.6.8'
|
||||
debugImplementation "androidx.compose.ui:ui-tooling:1.6.8"
|
||||
implementation 'androidx.fragment:fragment-ktx:1.8.1'
|
||||
implementation 'androidx.fragment:fragment-ktx:1.8.2'
|
||||
|
||||
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
|
||||
implementation "androidx.navigation:navigation-ui:$nav_version"
|
||||
|
@ -198,7 +199,7 @@ dependencies {
|
|||
implementation "androidx.work:work-runtime-ktx:$work_version"
|
||||
// androidTestImplementation "android.arch.work:work-testing:$work_version"
|
||||
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
|
@ -215,7 +216,7 @@ dependencies {
|
|||
implementation 'com.squareup.okhttp3:okhttp-tls:4.9.3'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:4.9.3'
|
||||
|
||||
googleApiImplementation "com.android.billingclient:billing-ktx:6.2.1"
|
||||
googleApiImplementation "com.android.billingclient:billing-ktx:7.0.0"
|
||||
|
||||
implementation('io.socket:socket.io-client:2.0.0') {
|
||||
exclude group: 'org.json', module: 'json'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||
TimeLimit Copyright <C> 2019 - 2024 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.
|
||||
|
@ -124,6 +124,14 @@
|
|||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name=".ui.diagnose.exception.DiagnoseExceptionActivity"
|
||||
android:theme="@style/AppTheme.Translucent"
|
||||
android:exported="false"
|
||||
android:excludeFromRecents="true"
|
||||
android:taskAffinity=":exception"
|
||||
android:launchMode="singleTop" />
|
||||
|
||||
<!-- system integration -->
|
||||
|
||||
<receiver android:name=".integration.platform.android.receiver.BootReceiver" android:exported="false">
|
||||
|
|
|
@ -219,7 +219,8 @@ data class AppStatusMessage(
|
|||
val title: String,
|
||||
val text: String,
|
||||
val subtext: String? = null,
|
||||
val showSwitchToDefaultUserOption: Boolean = false
|
||||
val showSwitchToDefaultUserOption: Boolean = false,
|
||||
val showErrorMessage: Boolean = false
|
||||
): Parcelable
|
||||
|
||||
data class BatteryStatus(
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2024 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
|
||||
|
@ -29,6 +29,7 @@ import io.timelimit.android.logic.DefaultAppLogic
|
|||
import io.timelimit.android.sync.actions.SignOutAtDeviceAction
|
||||
import io.timelimit.android.sync.actions.apply.ApplyActionUtil
|
||||
import io.timelimit.android.ui.MainActivity
|
||||
import io.timelimit.android.ui.diagnose.exception.DiagnoseExceptionActivity
|
||||
import io.timelimit.android.ui.notification.NotificationAreaSync
|
||||
|
||||
class BackgroundActionService: Service() {
|
||||
|
@ -44,7 +45,7 @@ class BackgroundActionService: Service() {
|
|||
fun prepareRevokeTemporarilyAllowed(context: Context) = Intent(context, BackgroundActionService::class.java)
|
||||
.putExtra(ACTION, ACTION_REVOKE_TEMPORARILY_ALLOWED_APPS)
|
||||
|
||||
fun getSwitchToDefaultUserIntent(context: Context) = PendingIntent.getService(
|
||||
fun getSwitchToDefaultUserIntent(context: Context): PendingIntent = PendingIntent.getService(
|
||||
context,
|
||||
PendingIntentIds.SWITCH_TO_DEFAULT_USER,
|
||||
Intent(context, BackgroundActionService::class.java)
|
||||
|
@ -57,14 +58,24 @@ class BackgroundActionService: Service() {
|
|||
.putExtra(EXTRA_NOTIFICATION_TYPE, type)
|
||||
.putExtra(EXTRA_NOTIFICATION_ID, id)
|
||||
|
||||
fun getOpenAppIntent(context: Context) = PendingIntent.getActivity(
|
||||
fun getOpenAppIntent(context: Context): PendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
PendingIntentIds.OPEN_MAIN_APP,
|
||||
Intent(context, MainActivity::class.java),
|
||||
PendingIntentIds.PENDING_INTENT_FLAGS
|
||||
)
|
||||
|
||||
fun getSyncNotificationsPendingIntent(context: Context) = PendingIntent.getService(
|
||||
fun getOpenAppWithErrorIntent(context: Context): PendingIntent = PendingIntent.getActivities(
|
||||
context,
|
||||
PendingIntentIds.OPEN_MAIN_APP_WITH_ERROR,
|
||||
arrayOf(
|
||||
Intent(context, MainActivity::class.java).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
|
||||
Intent(context, DiagnoseExceptionActivity::class.java).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
),
|
||||
PendingIntentIds.PENDING_INTENT_FLAGS
|
||||
)
|
||||
|
||||
fun getSyncNotificationsPendingIntent(context: Context): PendingIntent = PendingIntent.getService(
|
||||
context,
|
||||
PendingIntentIds.SYNC_NOTIFICATIONS,
|
||||
Intent(context, BackgroundActionService::class.java)
|
||||
|
|
|
@ -86,7 +86,12 @@ class BackgroundService: Service() {
|
|||
.setContentTitle(appStatusMessage.title)
|
||||
.setContentText(appStatusMessage.text)
|
||||
.setSubText(appStatusMessage.subtext)
|
||||
.setContentIntent(BackgroundActionService.getOpenAppIntent(context))
|
||||
.setContentIntent(
|
||||
if (appStatusMessage.showErrorMessage)
|
||||
BackgroundActionService.getOpenAppWithErrorIntent(context)
|
||||
else
|
||||
BackgroundActionService.getOpenAppIntent(context)
|
||||
)
|
||||
.setWhen(0)
|
||||
.setShowWhen(false)
|
||||
.setSound(null)
|
||||
|
|
|
@ -254,6 +254,7 @@ object PendingIntentIds {
|
|||
const val OPEN_UPDATER = 6
|
||||
const val U2F_NFC_DISCOVERY = 7
|
||||
const val U2F_USB_RESPONSE = 8
|
||||
const val OPEN_MAIN_APP_WITH_ERROR = 9
|
||||
val DYNAMIC_NOTIFICATION_RANGE = 100..10000
|
||||
|
||||
val PENDING_INTENT_FLAGS = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
|
|
|
@ -904,7 +904,8 @@ class BackgroundTaskLogic(val appLogic: AppLogic) {
|
|||
appLogic.platformIntegration.setAppStatusMessage(AppStatusMessage(
|
||||
appLogic.context.getString(R.string.background_logic_error),
|
||||
appLogic.context.getString(R.string.background_logic_error_internal),
|
||||
showSwitchToDefaultUserOption = deviceRelatedData.canSwitchToDefaultUser
|
||||
showSwitchToDefaultUserOption = deviceRelatedData.canSwitchToDefaultUser,
|
||||
showErrorMessage = true
|
||||
))
|
||||
appLogic.platformIntegration.setShowBlockingOverlay(false)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2024 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.diagnose.exception
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import io.timelimit.android.logic.DefaultAppLogic
|
||||
|
||||
class DiagnoseExceptionActivity: FragmentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
val ex = DefaultAppLogic.with(this).backgroundTaskLogic.lastLoopException.value
|
||||
|
||||
if (ex != null) setContent {
|
||||
DiagnoseExceptionDialog(
|
||||
message = ExceptionUtil.formatInterpreted(this, ex),
|
||||
close = { finish() }
|
||||
)
|
||||
} else finish()
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2024 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
|
||||
|
@ -37,7 +37,7 @@ class DiagnoseExceptionDialogFragment: DialogFragment() {
|
|||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val message = ExceptionUtil.format(requireArguments().getSerializable(EXCEPTION) as Exception)
|
||||
val message = ExceptionUtil.formatInterpreted(requireContext(), requireArguments().getSerializable(EXCEPTION) as Exception)
|
||||
|
||||
return AlertDialog.Builder(requireContext(), theme)
|
||||
.setMessage(message)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2024 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
|
||||
|
@ -15,11 +15,26 @@
|
|||
*/
|
||||
package io.timelimit.android.ui.diagnose.exception
|
||||
|
||||
import android.content.Context
|
||||
import io.timelimit.android.R
|
||||
import io.timelimit.android.integration.platform.android.foregroundapp.InstanceIdForegroundAppHelper.InstanceIdException
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
|
||||
object ExceptionUtil {
|
||||
fun format(tr: Throwable): String = StringWriter().let { sw ->
|
||||
fun formatInterpreted(context: Context, tr: Throwable): String {
|
||||
val explain = when (tr) {
|
||||
is InstanceIdException.EventsNotSortedByTimestamp -> context.getString(R.string.background_logic_errpr_detailed_instanceid_sorting)
|
||||
else -> null
|
||||
}
|
||||
|
||||
val tr2 = formatSimple(tr)
|
||||
|
||||
return if (explain != null) "$explain\n\n$tr2"
|
||||
else tr2
|
||||
}
|
||||
|
||||
private fun formatSimple(tr: Throwable): String = StringWriter().let { sw ->
|
||||
PrintWriter(sw).let { pw ->
|
||||
tr.printStackTrace(pw)
|
||||
pw.flush()
|
||||
|
|
|
@ -181,7 +181,7 @@ object AccountDeletion {
|
|||
)
|
||||
|
||||
if (result == SnackbarResult.ActionPerformed) updateState {
|
||||
it.copy(errorDialog = ExceptionUtil.format(ex))
|
||||
it.copy(errorDialog = ExceptionUtil.formatInterpreted(logic.context, ex))
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
|
|
@ -160,7 +160,7 @@ object MailAuthentication {
|
|||
)
|
||||
|
||||
if (result == SnackbarResult.ActionPerformed) {
|
||||
val message = ExceptionUtil.format(ex)
|
||||
val message = ExceptionUtil.formatInterpreted(logic.context, ex)
|
||||
|
||||
updateState { it.withError(error = ErrorDialog.ExceptionDetails(message)) }
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2024 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
|
||||
|
@ -181,7 +181,7 @@ object DeviceOwnerHandling {
|
|||
)
|
||||
|
||||
if (result == SnackbarResult.ActionPerformed) updateState {
|
||||
it.copy(dialog = OwnerState.ErrorDialog(ExceptionUtil.format(ex)))
|
||||
it.copy(dialog = OwnerState.ErrorDialog(ExceptionUtil.formatInterpreted(logic.context, ex)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2024 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
|
||||
|
@ -363,7 +363,7 @@ object SetupParentHandling {
|
|||
)
|
||||
|
||||
if (result == SnackbarResult.ActionPerformed) updateState {
|
||||
it.copy(error = ExceptionUtil.format(ex))
|
||||
it.copy(error = ExceptionUtil.formatInterpreted(logic.context, ex))
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
- verbesserter Umgang mit Fehlern im Hintergrund
|
||||
- enthaltene Komponenten aktualisiert
|
||||
- Probleme bei der Anmeldung behoben
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
- improved handling of errors in the background
|
||||
- update contained software
|
||||
- fix issues during login
|
||||
|
|
|
@ -197,6 +197,12 @@
|
|||
<string name="background_logic_opening_lockscreen">Sperrbildschirm wird geöffnet</string>
|
||||
<string name="background_logic_permission_sanction_title">Berechtigung fehlt</string>
|
||||
<string name="background_logic_permission_sanction_text">nehme an, dass alles verwendet wird</string>
|
||||
<string name="background_logic_errpr_detailed_instanceid_sorting">Es gibt ein Problem mit der
|
||||
Nutzungsstatisitkdatenbank Ihres Gerätes.
|
||||
Deshalb kann TimeLimit nicht zuverlässig erkennen, welche App verwendet wird.
|
||||
Dieses Problem kann nur behoben werden durch vier Tagen Geduld oder das Zurücksetzen des Gerätes.
|
||||
Eine Neuinstallation von TimeLimit hilft NICHT.
|
||||
</string>
|
||||
|
||||
<string name="background_logic_temporarily_allowed_title">Apps wurden vorübergehend erlaubt</string>
|
||||
<string name="background_logic_temporarily_allowed_text">Zum Rückgängig machen hier tippen oder Bildschirm ausschalten</string>
|
||||
|
|
|
@ -240,6 +240,12 @@
|
|||
<string name="background_logic_opening_lockscreen">Opening lock screen</string>
|
||||
<string name="background_logic_permission_sanction_title">Missing permission</string>
|
||||
<string name="background_logic_permission_sanction_text">assuming that everything is used</string>
|
||||
<string name="background_logic_errpr_detailed_instanceid_sorting">There is an issue with
|
||||
the data in the usage stats database of your device.
|
||||
Due to that, TimeLimit can not reliable detect the running Apps.
|
||||
You can do nothing to solve this except waiting for four days or doing a reset of the whole device.
|
||||
Reinstalling TimeLimit does NOT help.
|
||||
</string>
|
||||
|
||||
<string name="background_logic_temporarily_allowed_title">Apps are temporarily allowed</string>
|
||||
<string name="background_logic_temporarily_allowed_text">Tap here or turn screen off to undo</string>
|
||||
|
|
|
@ -32,6 +32,10 @@
|
|||
<item name="colorAccent">@color/white</item>
|
||||
</style>
|
||||
|
||||
<style name="AppTheme.Translucent" parent="AppTheme">
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
</style>
|
||||
|
||||
<!-- from https://stackoverflow.com/a/46286184 -->
|
||||
<style name="BottomSheetDialog" parent="Theme.MaterialComponents.DayNight.BottomSheetDialog">
|
||||
<item name="colorPrimary">@color/colorPrimary</item>
|
||||
|
|
10
build.gradle
10
build.gradle
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2024 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
|
||||
|
@ -15,10 +15,10 @@
|
|||
*/
|
||||
|
||||
plugins {
|
||||
id 'com.android.application' version '8.5.0' apply false
|
||||
id 'com.android.library' version '8.5.0' apply false
|
||||
id 'org.jetbrains.kotlin.android' version "1.9.20" apply false
|
||||
id 'com.google.devtools.ksp' version '1.8.21-1.0.11' apply false
|
||||
id 'com.android.application' version '8.5.1' apply false
|
||||
id 'com.android.library' version '8.5.1' apply false
|
||||
id 'org.jetbrains.kotlin.android' version "1.9.21" apply false
|
||||
id 'com.google.devtools.ksp' version '1.9.21-1.0.16' apply false
|
||||
id 'androidx.navigation.safeargs' version '2.6.0' apply false
|
||||
id 'com.squareup.wire' version '4.4.3' apply false
|
||||
}
|
|
@ -7,7 +7,6 @@
|
|||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
android.useAndroidX=true
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
org.gradle.jvmargs=-Xmx4096m
|
||||
# When configured, Gradle will run in incubating parallel mode.
|
||||
# This option should only be used with decoupled projects. More details, visit
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue