mirror of
https://codeberg.org/timelimit/timelimit-android.git
synced 2025-10-03 17:59:51 +02:00
Compare commits
6 commits
release-7.
...
master
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6c02c4e4c7 | ||
![]() |
c746770e89 | ||
![]() |
0505fa0f8b | ||
![]() |
4498aa191f | ||
![]() |
3d49bd8229 | ||
![]() |
abe6d47a96 |
19 changed files with 141 additions and 40 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,3 +10,4 @@
|
|||
/captures
|
||||
.externalNativeBuild
|
||||
.idea
|
||||
.kotlin
|
||||
|
|
|
@ -21,18 +21,18 @@ plugins {
|
|||
id "androidx.navigation.safeargs.kotlin"
|
||||
id 'kotlin-kapt'
|
||||
id 'com.squareup.wire'
|
||||
id("org.jetbrains.kotlin.plugin.compose") version "2.0.21"
|
||||
id("org.jetbrains.kotlin.plugin.compose") version "2.1.10"
|
||||
}
|
||||
|
||||
android {
|
||||
namespace 'io.timelimit.android'
|
||||
compileSdk 35
|
||||
compileSdk 36
|
||||
defaultConfig {
|
||||
applicationId "io.timelimit.android"
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 35
|
||||
versionCode 223
|
||||
versionName "7.2.4"
|
||||
targetSdkVersion 36
|
||||
versionCode 224
|
||||
versionName "7.3.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
kapt {
|
||||
arguments {
|
||||
|
@ -172,7 +172,7 @@ dependencies {
|
|||
def paging_version = "3.3.6"
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.1.10"
|
||||
implementation 'androidx.appcompat:appcompat:1.7.1'
|
||||
implementation 'androidx.core:core:1.16.0'
|
||||
implementation 'androidx.cardview:cardview:1.0.0'
|
||||
|
@ -201,8 +201,8 @@ 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.3'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0'
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0'
|
||||
|
||||
testImplementation 'junit:junit:4.13.2'
|
||||
androidTestImplementation 'androidx.test:runner:1.6.2'
|
||||
|
@ -218,7 +218,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:7.1.1"
|
||||
googleApiImplementation "com.android.billingclient:billing-ktx:8.0.0"
|
||||
|
||||
implementation('io.socket:socket.io-client:2.0.0') {
|
||||
exclude group: 'org.json', module: 'json'
|
||||
|
@ -230,5 +230,5 @@ dependencies {
|
|||
|
||||
implementation 'com.google.zxing:core:3.3.3'
|
||||
|
||||
api "com.squareup.wire:wire-runtime:4.4.3"
|
||||
api "com.squareup.wire:wire-runtime:5.3.5"
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2024 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2025 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
|
||||
|
@ -69,13 +69,13 @@ abstract class UsedTimeDao {
|
|||
|
||||
// breaking it into multiple lines causes issues during compilation ...
|
||||
// this warns about an unused column, but this column is used in the ORDER BY
|
||||
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
|
||||
@SuppressWarnings(RoomWarnings.QUERY_MISMATCH)
|
||||
@Query("SELECT 2 AS type, start_time_of_day AS startMinuteOfDay, end_time_of_day AS endMinuteOfDay, used_time AS duration, day_of_epoch AS day, NULL AS lastUsage, NULL AS maxSessionDuration, NULL AS pauseDuration, category.id AS categoryId, category.title AS categoryTitle FROM used_time JOIN category ON (used_time.category_id = category.id) WHERE category.id = :categoryId UNION ALL SELECT 1 AS type, start_minute_of_day AS startMinuteOfDay, end_minute_of_day AS endMinuteOfDay, last_session_duration AS duration, NULL AS day, last_usage AS lastUsage, max_session_duration AS maxSessionDuration, session_pause_duration AS pauseDuration, category.id AS categoryId, category.title AS categoryTitle FROM session_duration JOIN category ON (session_duration.category_id = category.id) WHERE category.id = :categoryId ORDER BY type, day DESC, lastUsage DESC, startMinuteOfDay, endMinuteOfDay, categoryId")
|
||||
abstract fun getUsedTimeListItemsByCategoryId(categoryId: String): Flow<List<UsedTimeListItem>>
|
||||
|
||||
// breaking it into multiple lines causes issues during compilation ...
|
||||
// this warns about an unused column, but this column is used in the ORDER BY
|
||||
@SuppressWarnings(RoomWarnings.CURSOR_MISMATCH)
|
||||
@SuppressWarnings(RoomWarnings.QUERY_MISMATCH)
|
||||
@Query("SELECT 2 AS type, start_time_of_day AS startMinuteOfDay, end_time_of_day AS endMinuteOfDay, used_time AS duration, day_of_epoch AS day, NULL AS lastUsage, NULL AS maxSessionDuration, NULL AS pauseDuration, category.id AS categoryId, category.title AS categoryTitle FROM used_time JOIN category ON (used_time.category_id = category.id) WHERE category.child_id = :userId UNION ALL SELECT 1 AS type, start_minute_of_day AS startMinuteOfDay, end_minute_of_day AS endMinuteOfDay, last_session_duration AS duration, NULL AS day, last_usage AS lastUsage, max_session_duration AS maxSessionDuration, session_pause_duration AS pauseDuration, category.id AS categoryId, category.title AS categoryTitle FROM session_duration JOIN category ON (session_duration.category_id = category.id) WHERE category.child_id = :userId ORDER BY type, day DESC, lastUsage DESC, startMinuteOfDay, endMinuteOfDay, categoryId")
|
||||
abstract fun getUsedTimeListItemsByUserId(userId: String): Flow<List<UsedTimeListItem>>
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2025 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
|
||||
|
@ -295,4 +295,7 @@ object ExperimentalFlags {
|
|||
|
||||
object ConsentFlags {
|
||||
const val APP_LIST_SYNC = 1L
|
||||
|
||||
// this is used internally
|
||||
const val BLOCK_USER_SWITCH_BY_DEFAULT = 2L
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2025 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
|
||||
|
@ -73,4 +73,5 @@ data class DeviceRelatedData (
|
|||
}
|
||||
|
||||
fun isExperimentalFlagSetSync(flags: Long) = (experimentalFlags and flags) == flags
|
||||
fun isConsentFlagSet(flags: Long) = (consentFlags and flags) == flags
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2025 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
|
||||
|
@ -27,6 +27,10 @@ import io.timelimit.android.integration.platform.PlatformFeature
|
|||
object AndroidFeatures {
|
||||
private const val FEATURE_ADB = "adb"
|
||||
private const val FEATURE_CONFIG_PRIVATE_DNS = "dns"
|
||||
const val FEATURE_ADD_USER = "add_user"
|
||||
const val FEATURE_USER_SWITCH = "user_switch"
|
||||
private const val FEATURE_VPN = "vpn"
|
||||
private const val FEATURE_UNKNOWN_SOURCES = "unknown_sources"
|
||||
|
||||
fun applyBlockedFeatures(features: Set<String>, policyManager: DevicePolicyManager, admin: ComponentName): Boolean {
|
||||
fun apply(feature: String, restriction: String) {
|
||||
|
@ -40,6 +44,18 @@ object AndroidFeatures {
|
|||
apply(FEATURE_CONFIG_PRIVATE_DNS, UserManager.DISALLOW_CONFIG_PRIVATE_DNS)
|
||||
}
|
||||
|
||||
apply(FEATURE_ADD_USER, UserManager.DISALLOW_ADD_USER)
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.P) {
|
||||
apply(FEATURE_USER_SWITCH, UserManager.DISALLOW_USER_SWITCH)
|
||||
}
|
||||
|
||||
apply(FEATURE_VPN, UserManager.DISALLOW_CONFIG_VPN)
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.Q) {
|
||||
apply(FEATURE_UNKNOWN_SOURCES, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -60,6 +76,30 @@ object AndroidFeatures {
|
|||
)
|
||||
}
|
||||
|
||||
result.add(PlatformFeature(
|
||||
id = FEATURE_ADD_USER,
|
||||
title = context.getString(R.string.dummy_app_feature_add_user)
|
||||
))
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.P) {
|
||||
result.add(PlatformFeature(
|
||||
id = FEATURE_USER_SWITCH,
|
||||
title = context.getString(R.string.dummy_app_feature_switch_user)
|
||||
))
|
||||
}
|
||||
|
||||
result.add(PlatformFeature(
|
||||
id = FEATURE_VPN,
|
||||
title = context.getString(R.string.dummy_app_feature_vpn)
|
||||
))
|
||||
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.Q) {
|
||||
result.add(PlatformFeature(
|
||||
id = FEATURE_UNKNOWN_SOURCES,
|
||||
title = context.getString(R.string.dummy_app_feature_unknown_sources)
|
||||
))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
|
@ -507,7 +507,6 @@ class AndroidIntegration(context: Context): PlatformIntegration(maximumProtectio
|
|||
|
||||
if (enableLockdown) {
|
||||
// disable problematic features
|
||||
policyManager.addUserRestriction(deviceAdmin, UserManager.DISALLOW_ADD_USER)
|
||||
policyManager.addUserRestriction(deviceAdmin, UserManager.DISALLOW_FACTORY_RESET)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
|
@ -557,7 +556,6 @@ class AndroidIntegration(context: Context): PlatformIntegration(maximumProtectio
|
|||
}
|
||||
} else /* disable lockdown */ {
|
||||
// enable problematic features
|
||||
policyManager.clearUserRestriction(deviceAdmin, UserManager.DISALLOW_ADD_USER)
|
||||
policyManager.clearUserRestriction(deviceAdmin, UserManager.DISALLOW_FACTORY_RESET)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2025 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
|
||||
|
@ -65,6 +65,11 @@ class AppSetupLogic(private val appLogic: AppLogic) {
|
|||
appLogic.database.deleteAllData()
|
||||
|
||||
appLogic.database.config().setCustomServerUrlSync(customServerUrl)
|
||||
|
||||
appLogic.database.config().setConsentFlagSync(
|
||||
ConsentFlags.BLOCK_USER_SWITCH_BY_DEFAULT,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
run {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2025 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
|
||||
|
@ -19,10 +19,12 @@ import io.timelimit.android.async.Threads
|
|||
import io.timelimit.android.data.invalidation.Observer
|
||||
import io.timelimit.android.data.invalidation.Table
|
||||
import io.timelimit.android.data.model.CategoryApp
|
||||
import io.timelimit.android.data.model.ConsentFlags
|
||||
import io.timelimit.android.data.model.ExperimentalFlags
|
||||
import io.timelimit.android.data.model.UserType
|
||||
import io.timelimit.android.data.model.derived.UserRelatedData
|
||||
import io.timelimit.android.integration.platform.ProtectionLevel
|
||||
import io.timelimit.android.integration.platform.android.AndroidFeatures
|
||||
import io.timelimit.android.integration.platform.android.AndroidIntegrationApps
|
||||
import io.timelimit.android.logic.blockingreason.CategoryHandlingCache
|
||||
import java.lang.ref.WeakReference
|
||||
|
@ -107,12 +109,23 @@ class SuspendAppsLogic(private val appLogic: AppLogic): Observer {
|
|||
val hasManagedFeatures = featureCategoryApps.isNotEmpty()
|
||||
val enableBlocking = isRestrictedUser && (enableBlockingAtSystemLevel || hasManagedFeatures)
|
||||
|
||||
val blockUserSwitchByDefault =
|
||||
userAndDeviceRelatedData?.deviceRelatedData?.isConsentFlagSet(ConsentFlags.BLOCK_USER_SWITCH_BY_DEFAULT) == true
|
||||
&& userAndDeviceRelatedData.userRelatedData?.user?.type == UserType.Child
|
||||
|
||||
val featureToAllowDefaults = mapOf(
|
||||
AndroidFeatures.FEATURE_ADD_USER to false,
|
||||
AndroidFeatures.FEATURE_USER_SWITCH to !blockUserSwitchByDefault
|
||||
)
|
||||
|
||||
if (!enableBlocking) {
|
||||
lastDefaultCategory = null
|
||||
lastAllowedCategoryList = emptySet()
|
||||
lastCategoryApps = emptyList()
|
||||
applySuspendedApps(emptyList())
|
||||
applyBlockedFeatures(emptySet())
|
||||
applyBlockedFeatures(
|
||||
featureToAllowDefaults.filter { !it.value }.map { it.key }.toSet()
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -191,9 +204,15 @@ class SuspendAppsLogic(private val appLogic: AppLogic): Observer {
|
|||
val deviceSpecificFeatureIdentifiers = deviceSpecificFeatures.map { it.appSpecifierString }.toSet()
|
||||
val globalFeatures = featureCategoryApps.filter { !deviceSpecificFeatureIdentifiers.contains(it.appSpecifierString) }
|
||||
val effectiveFeatures = deviceSpecificFeatures + globalFeatures
|
||||
val featuresToBlock = effectiveFeatures.filter { !categoryIdsToAllow.contains(it.categoryId) }
|
||||
.map { it.appSpecifierString.substring(DummyApps.FEATURE_APP_PREFIX.length) }
|
||||
.toSet()
|
||||
|
||||
val featuresToAllow = featureToAllowDefaults + effectiveFeatures.associate {
|
||||
Pair(
|
||||
it.appSpecifierString.substring(DummyApps.FEATURE_APP_PREFIX.length),
|
||||
categoryIdsToAllow.contains(it.categoryId)
|
||||
)
|
||||
}
|
||||
|
||||
val featuresToBlock = featuresToAllow.filter { !it.value }.map { it.key }.toSet()
|
||||
|
||||
applySuspendedApps(appsToBlock)
|
||||
applyBlockedFeatures(featuresToBlock)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2024 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2025 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
|
||||
|
@ -23,6 +23,7 @@ import io.timelimit.android.async.Threads
|
|||
import io.timelimit.android.coroutines.executeAndWait
|
||||
import io.timelimit.android.data.backup.DatabaseBackup
|
||||
import io.timelimit.android.data.devicename.DeviceName
|
||||
import io.timelimit.android.data.model.ConsentFlags
|
||||
import io.timelimit.android.logic.AppLogic
|
||||
import io.timelimit.android.sync.ApplyServerDataStatus
|
||||
import io.timelimit.android.sync.network.NewDeviceInfo
|
||||
|
@ -333,6 +334,11 @@ object SetupParentHandling {
|
|||
database.config().setDeviceAuthTokenSync(result.deviceAuthToken)
|
||||
database.config().setEnableBackgroundSync(state.backgroundSync)
|
||||
|
||||
database.config().setConsentFlagSync(
|
||||
ConsentFlags.BLOCK_USER_SWITCH_BY_DEFAULT,
|
||||
true
|
||||
)
|
||||
|
||||
ApplyServerDataStatus.applyServerDataStatusSync(result.serverDataStatus, logic.database, logic.platformIntegration)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2025 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
|
||||
|
@ -74,9 +74,14 @@ class ActivityPurchaseModel(application: Application): AndroidViewModel(applicat
|
|||
clientMutex.withLock {
|
||||
if (_billingClient == null) {
|
||||
_billingClient = BillingClient.newBuilder(getApplication())
|
||||
.enablePendingPurchases()
|
||||
.setListener(purchaseUpdatedListener)
|
||||
.build()
|
||||
.enablePendingPurchases(
|
||||
PendingPurchasesParams
|
||||
.newBuilder()
|
||||
.enableOneTimeProducts()
|
||||
.build()
|
||||
)
|
||||
.setListener(purchaseUpdatedListener)
|
||||
.build()
|
||||
}
|
||||
|
||||
val initBillingClient = _billingClient!!
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2023 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2025 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
|
||||
|
@ -24,6 +24,7 @@ import io.timelimit.android.coroutines.executeAndWait
|
|||
import io.timelimit.android.coroutines.runAsync
|
||||
import io.timelimit.android.data.backup.DatabaseBackup
|
||||
import io.timelimit.android.data.devicename.DeviceName
|
||||
import io.timelimit.android.data.model.ConsentFlags
|
||||
import io.timelimit.android.livedata.castDown
|
||||
import io.timelimit.android.logic.AppLogic
|
||||
import io.timelimit.android.logic.DefaultAppLogic
|
||||
|
@ -70,6 +71,11 @@ class SetupRemoteChildViewModel(application: Application): AndroidViewModel(appl
|
|||
logic.database.config().setOwnDeviceIdSync(registerResponse.ownDeviceId)
|
||||
logic.database.config().setDeviceAuthTokenSync(registerResponse.deviceAuthToken)
|
||||
|
||||
logic.database.config().setConsentFlagSync(
|
||||
ConsentFlags.BLOCK_USER_SWITCH_BY_DEFAULT,
|
||||
true
|
||||
)
|
||||
|
||||
ApplyServerDataStatus.applyServerDataStatusSync(clientStatusResponse, logic.database, logic.platformIntegration)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
- Abstürze in bestimmten Fällen behoben
|
||||
- Funktionsumfang bei Verwendung der Geräte-Besitzer-Berechtigung erweitert
|
||||
- enthaltene Komponenten aktualisiert
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
- fix crashes in specific scenarios
|
||||
- add more features for users of the device owner permission
|
||||
- update contained software
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
TimeLimit Copyright <C> 2019 - 2024 Jonas Lochmann
|
||||
TimeLimit Copyright <C> 2019 - 2025 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.
|
||||
|
@ -1752,6 +1752,10 @@
|
|||
<string name="dummy_app_unassigned_system_image_app">nicht zugeordnete Apps von der Systempartition</string>
|
||||
<string name="dummy_app_feature_adb">Entwickleroptionen</string>
|
||||
<string name="dummy_app_feature_dns">DNS-Einstellungen</string>
|
||||
<string name="dummy_app_feature_add_user">Systembenutzer erstellen</string>
|
||||
<string name="dummy_app_feature_switch_user">Systembenutzer wechseln</string>
|
||||
<string name="dummy_app_feature_vpn">VPN konfigurieren</string>
|
||||
<string name="dummy_app_feature_unknown_sources">Apps aus unbekannten Quellen installieren</string>
|
||||
<string name="dummy_app_activity_audio">Hintergrundmusikwiedergabe</string>
|
||||
|
||||
<string name="notify_permission_title">Benachrichtigungen</string>
|
||||
|
|
|
@ -1804,6 +1804,10 @@
|
|||
<string name="dummy_app_unassigned_system_image_app">not assigned Apps from the system image</string>
|
||||
<string name="dummy_app_feature_adb">Developer Options</string>
|
||||
<string name="dummy_app_feature_dns">DNS Settings</string>
|
||||
<string name="dummy_app_feature_add_user">Create System User</string>
|
||||
<string name="dummy_app_feature_switch_user">Switch System User</string>
|
||||
<string name="dummy_app_feature_vpn">Configure VPN</string>
|
||||
<string name="dummy_app_feature_unknown_sources">Install Apps from unknown sources</string>
|
||||
<string name="dummy_app_activity_audio">Background Audio Playback</string>
|
||||
|
||||
<string name="notify_permission_title">Notifications</string>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* TimeLimit Copyright <C> 2019 - 2022 Jonas Lochmann
|
||||
* TimeLimit Copyright <C> 2019 - 2025 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
|
||||
|
@ -42,7 +42,7 @@ object BillingClient {
|
|||
enum class ProductType { INAPP }
|
||||
|
||||
object Builder {
|
||||
fun enablePendingPurchases() = this
|
||||
fun enablePendingPurchases(params: PendingPurchasesParams) = this
|
||||
fun setListener(listener: PurchasesUpdatedListener) = this
|
||||
fun build() = BillingClient
|
||||
}
|
||||
|
@ -143,4 +143,13 @@ object QueryPurchasesParams {
|
|||
fun newBuilder() = this
|
||||
fun setProductType(type: BillingClient.ProductType) = this
|
||||
fun build() = this
|
||||
}
|
||||
|
||||
object PendingPurchasesParams {
|
||||
object Builder {
|
||||
fun enableOneTimeProducts() = this
|
||||
fun build() = PendingPurchasesParams
|
||||
}
|
||||
|
||||
fun newBuilder() = Builder
|
||||
}
|
|
@ -15,10 +15,10 @@
|
|||
*/
|
||||
|
||||
plugins {
|
||||
id 'com.android.application' version '8.10.1' apply false
|
||||
id 'com.android.library' version '8.10.1' apply false
|
||||
id 'com.android.application' version '8.11.1' apply false
|
||||
id 'com.android.library' version '8.11.1' apply false
|
||||
id 'org.jetbrains.kotlin.android' version "2.0.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
|
||||
id 'com.squareup.wire' version '5.3.5' apply false
|
||||
}
|
4
gradle/wrapper/gradle-wrapper.properties
vendored
4
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -2,5 +2,5 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
||||
distributionSha256Sum=89d4e70e4e84e2d2dfbb63e4daa53e21b25017cc70c37e4eea31ee51fb15098a
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
|
||||
distributionSha256Sum=20f1b1176237254a6fc204d8434196fa11a4cfb387567519c61556e8710aed78
|
Loading…
Add table
Add a link
Reference in a new issue