Skip to content

Commit

Permalink
feat: execute timing background sync with WorkManager
Browse files Browse the repository at this point in the history
feat: add `syncUserData` to new api facade
refactor: remove schedule exact alarm permission (checking, string res, etc.)
  • Loading branch information
WhiredPlanck committed Oct 7, 2024
1 parent 6b7b29f commit 7158a2b
Show file tree
Hide file tree
Showing 15 changed files with 52 additions and 179 deletions.
1 change: 0 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ SPDX-License-Identifier: GPL-3.0-or-later
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name ="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

Expand Down
4 changes: 2 additions & 2 deletions app/src/main/assets/shared/trime.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -984,8 +984,8 @@ preset_keys:
WebSearch: {label: 搜索網頁, command: web_search, option: "%4$s"} #搜索,其他view、dial、edit、search等intent,參考安卓的intent文檔:https://developer.android.com/reference/android/content/Intent.html
Search: {label: 搜索, command: search, option: "%1$s"} #搜索短信、字典等
Share: {label: 分享, command: send, option: "%s"} #分享指定文本: %s或者%1$s爲當前字符
Deploy: {label: 部署, command: broadcast, option: "com.osfans.trime.deploy"}
Sync: {label: 同步, command: broadcast, option: "com.osfans.trime.sync"}
Deploy: {label: 部署, command: broadcast, option: "com.osfans.trime.DEPLOY"}
Sync: {label: 同步, command: broadcast, option: "com.osfans.trime.SYNC"}
RepeatCommit: { label: 重复, command: commit, option: "%1$s" } #重复输入刚上屏的内容

preset_keyboards:
Expand Down
24 changes: 24 additions & 0 deletions app/src/main/java/com/osfans/trime/TrimeApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,17 @@ import android.content.Intent
import android.os.Process
import android.util.Log
import androidx.preference.PreferenceManager
import androidx.work.Configuration
import androidx.work.WorkManager
import com.osfans.trime.data.db.ClipboardHelper
import com.osfans.trime.data.db.CollectionHelper
import com.osfans.trime.data.db.DraftHelper
import com.osfans.trime.data.prefs.AppPrefs
import com.osfans.trime.ui.main.LogActivity
import com.osfans.trime.worker.BackgroundSyncWork
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import timber.log.Timber
import kotlin.system.exitProcess
Expand Down Expand Up @@ -116,9 +120,29 @@ class TrimeApplication : Application() {
ClipboardHelper.init(applicationContext)
CollectionHelper.init(applicationContext)
DraftHelper.init(applicationContext)

initializeWorkManagerIfAndroidForgotIt()
startWorkManager()
} catch (e: Exception) {
e.fillInStackTrace()
return
}
}

private fun initializeWorkManagerIfAndroidForgotIt() {
if (!WorkManager.isInitialized()) {
WorkManager.initialize(
applicationContext,
Configuration
.Builder()
.build(),
)
}
}

private fun startWorkManager() {
coroutineScope.launch {
BackgroundSyncWork.start(applicationContext)
}
}
}
5 changes: 5 additions & 0 deletions app/src/main/java/com/osfans/trime/core/Rime.kt
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,11 @@ class Rime :
getRimeCandidates(startIndex, limit) ?: emptyArray()
}

override suspend fun syncUserData(): Boolean =
withRimeContext {
syncRimeUserData()
}

private fun handleRimeNotification(notif: RimeNotification<*>) {
when (notif) {
is RimeNotification.SchemaNotification -> schemaItemCached = notif.value
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/osfans/trime/core/RimeApi.kt
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,6 @@ interface RimeApi {
startIndex: Int,
limit: Int,
): Array<CandidateItem>

suspend fun syncUserData(): Boolean
}
2 changes: 2 additions & 0 deletions app/src/main/java/com/osfans/trime/daemon/RimeDaemon.kt
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,6 @@ object RimeDaemon {
}
}
}

suspend fun syncUserData() = realRime.syncUserData()
}
87 changes: 11 additions & 76 deletions app/src/main/java/com/osfans/trime/ime/broadcast/IntentReceiver.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,101 +4,43 @@

package com.osfans.trime.ime.broadcast

import android.app.AlarmManager
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.os.PowerManager.PARTIAL_WAKE_LOCK
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.osfans.trime.R
import com.osfans.trime.core.Rime
import com.osfans.trime.daemon.RimeDaemon
import com.osfans.trime.data.prefs.AppPrefs
import com.osfans.trime.ime.core.TrimeInputMethodService
import com.osfans.trime.util.toast
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import splitties.systemservices.alarmManager
import splitties.systemservices.powerManager
import timber.log.Timber
import java.util.Calendar
import java.util.concurrent.TimeUnit

/** 接收 Intent 廣播事件 */
class IntentReceiver :
BroadcastReceiver(),
CoroutineScope by MainScope() {
class IntentReceiver(
private val service: TrimeInputMethodService,
) : BroadcastReceiver() {
override fun onReceive(
context: Context,
intent: Intent,
) {
val command = intent.action ?: return
Timber.d("Received Command = %s", command)
Timber.d("Received command: $command")
when (command) {
COMMAND_DEPLOY ->
launch {
service.lifecycleScope.launch {
withContext(Dispatchers.IO) {
RimeDaemon.restartRime(true)
}
context.toast(R.string.deploy_finish, Toast.LENGTH_LONG)
}
COMMAND_SYNC ->
launch {
withContext(Dispatchers.IO) {
Rime.syncRimeUserData()
RimeDaemon.restartRime(true)
}
}
COMMAND_TIMING_SYNC ->
launch {
withContext(Dispatchers.IO) {
// 获取唤醒锁
val wakeLock =
powerManager.newWakeLock(PARTIAL_WAKE_LOCK, "com.osfans.trime:WakeLock")
wakeLock.acquire(600000) // 10分钟超时
val cal = Calendar.getInstance()
val triggerTime = cal.timeInMillis + TimeUnit.DAYS.toMillis(1) // 下次同步时间
AppPrefs.defaultInstance().profile.timingBackgroundSyncSetTime =
triggerTime // 更新定时同步偏好值
// 设置待发送的同步事件
val pendingIntent =
PendingIntent.getBroadcast(
context,
0,
Intent(COMMAND_TIMING_SYNC),
if (VERSION.SDK_INT >= VERSION_CODES.M) {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
},
)
if (VERSION.SDK_INT < VERSION_CODES.S || alarmManager.canScheduleExactAlarms()) {
if (VERSION.SDK_INT >= VERSION_CODES.M) { // 根据SDK设置alarm任务
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
triggerTime,
pendingIntent,
)
} else {
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
triggerTime,
pendingIntent,
)
}
}

Rime.syncRimeUserData()
RimeDaemon.restartRime(true)
wakeLock.release() // 释放唤醒锁
}
service.lifecycleScope.launch(Dispatchers.IO) {
RimeDaemon.syncUserData()
}
else -> return
}
Expand All @@ -117,12 +59,6 @@ class IntentReceiver :
IntentFilter(COMMAND_SYNC),
ContextCompat.RECEIVER_NOT_EXPORTED,
)
ContextCompat.registerReceiver(
context,
this,
IntentFilter(COMMAND_TIMING_SYNC),
ContextCompat.RECEIVER_NOT_EXPORTED,
)
context.registerReceiver(this, IntentFilter(Intent.ACTION_SHUTDOWN))
}

Expand All @@ -131,8 +67,7 @@ class IntentReceiver :
}

companion object {
private const val COMMAND_DEPLOY = "com.osfans.trime.deploy"
private const val COMMAND_SYNC = "com.osfans.trime.sync"
private const val COMMAND_TIMING_SYNC = "com.osfans.trime.timing.sync"
private const val COMMAND_DEPLOY = "com.osfans.trime.DEPLOY"
private const val COMMAND_SYNC = "com.osfans.trime.SYNC"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
// and lead to a crash loop
Timber.d("onCreate")
mIntentReceiver =
IntentReceiver().also {
IntentReceiver(this).also {
it.registerReceiver(this)
}
postRimeJob {
Expand Down
62 changes: 3 additions & 59 deletions app/src/main/java/com/osfans/trime/ui/fragments/ProfileFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@

package com.osfans.trime.ui.fragments

import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Intent
import android.content.SharedPreferences
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.os.Bundle
import android.provider.DocumentsContract
import androidx.activity.result.contract.ActivityResultContracts
Expand All @@ -20,7 +14,6 @@ import androidx.preference.Preference
import androidx.preference.Preference.SummaryProvider
import androidx.preference.get
import com.osfans.trime.R
import com.osfans.trime.core.Rime
import com.osfans.trime.daemon.RimeDaemon
import com.osfans.trime.data.base.DataManager
import com.osfans.trime.data.prefs.AppPrefs
Expand All @@ -38,11 +31,8 @@ import com.osfans.trime.util.withLoadingDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import splitties.systemservices.alarmManager

class ProfileFragment :
PaddingPreferenceFragment(),
SharedPreferences.OnSharedPreferenceChangeListener {
class ProfileFragment : PaddingPreferenceFragment() {
private val viewModel: MainViewModel by activityViewModels()
private val prefs get() = AppPrefs.defaultInstance()

Expand Down Expand Up @@ -71,9 +61,8 @@ class ProfileFragment :
}
get<Preference>("profile_sync_user_data")?.setOnPreferenceClickListener {
lifecycleScope.launch {
this@ProfileFragment.context?.rimeActionWithResultDialog("rime.trime", "W", 1) {
Rime.syncRimeUserData()
RimeDaemon.restartRime(true)
requireContext().rimeActionWithResultDialog("rime.trime", "W", 1) {
RimeDaemon.syncUserData()
true
}
}
Expand Down Expand Up @@ -134,54 +123,9 @@ class ProfileFragment :
}
}

override fun onSharedPreferenceChanged(
sharedPreferences: SharedPreferences?,
key: String?,
) {
// 监听定时同步偏好设置
// 设置待发送的同步事件
val pendingIntent =
PendingIntent.getBroadcast(
context,
0,
Intent("com.osfans.trime.timing.sync"),
if (VERSION.SDK_INT >= VERSION_CODES.M) {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
},
)
if (prefs.profile.timingBackgroundSyncEnabled) {
val timeAtMillis = prefs.profile.timingBackgroundSyncSetTime
if (VERSION.SDK_INT < VERSION_CODES.S || alarmManager.canScheduleExactAlarms()) {
if (VERSION.SDK_INT >= VERSION_CODES.M) { // 根据 API Level 设置 alarm 任务
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
timeAtMillis,
pendingIntent,
)
} else {
alarmManager.setExact(
AlarmManager.RTC_WAKEUP,
timeAtMillis,
pendingIntent,
)
}
}
} else {
alarmManager.cancel(pendingIntent)
}
}

override fun onResume() {
super.onResume()
viewModel.setToolbarTitle(getString(R.string.pref_profile))
viewModel.disableTopOptionsMenu()
preferenceScreen.sharedPreferences?.registerOnSharedPreferenceChangeListener(this)
}

override fun onPause() {
super.onPause()
preferenceScreen.sharedPreferences?.unregisterOnSharedPreferenceChangeListener(this)
}
}
18 changes: 0 additions & 18 deletions app/src/main/java/com/osfans/trime/ui/main/PrefMainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ package com.osfans.trime.ui.main

import android.app.AlertDialog
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.view.Menu
import android.view.MenuItem
import android.view.ViewGroup
Expand Down Expand Up @@ -40,7 +38,6 @@ import com.osfans.trime.util.isStorageAvailable
import com.osfans.trime.util.progressBarDialogIndeterminate
import com.osfans.trime.util.rimeActionWithResultDialog
import kotlinx.coroutines.launch
import splitties.systemservices.alarmManager
import splitties.views.topPadding

class PrefMainActivity : AppCompatActivity() {
Expand Down Expand Up @@ -111,7 +108,6 @@ class PrefMainActivity : AppCompatActivity() {
startActivity(Intent(this, SetupActivity::class.java))
}

checkScheduleExactAlarmPermission()
checkNotificationPermission()

lifecycleScope.launch {
Expand Down Expand Up @@ -176,20 +172,6 @@ class PrefMainActivity : AppCompatActivity() {
loadingDialog = null
}

private fun checkScheduleExactAlarmPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && !alarmManager.canScheduleExactAlarms()) {
AlertDialog
.Builder(this)
.setIconAttribute(android.R.attr.alertDialogIcon)
.setTitle(R.string.schedule_exact_alarm_permission_title)
.setMessage(R.string.schedule_exact_alarm_permission_message)
.setPositiveButton(R.string.grant_permission) { _, _ ->
startActivity(Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM))
}.setNegativeButton(android.R.string.cancel, null)
.show()
}
}

private fun checkNotificationPermission() {
if (XXPermissions.isGranted(this, Permission.POST_NOTIFICATIONS)) {
return
Expand Down
Loading

0 comments on commit 7158a2b

Please sign in to comment.