Merge branch 'main' into mtls
This commit is contained in:
commit
eb0f8e0a8b
6 changed files with 113 additions and 28 deletions
|
|
@ -17,8 +17,8 @@ android {
|
|||
minSdkVersion 26
|
||||
targetSdkVersion 36
|
||||
|
||||
versionCode 53
|
||||
versionName "1.20.0"
|
||||
versionCode 54
|
||||
versionName "1.21.0"
|
||||
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,14 @@ class SubscriberService : Service() {
|
|||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
Log.d(TAG, "onStartCommand executed with startId: $startId")
|
||||
|
||||
// Safety check: ensure we're in foreground state. This handles edge cases where
|
||||
// onCreate() may not have been called or completed before onStartCommand(). See #1520.
|
||||
if (serviceNotification == null) {
|
||||
Log.d(TAG, "onStartCommand: Notification not set, initializing foreground state")
|
||||
initializeForegroundState()
|
||||
}
|
||||
|
||||
if (intent != null) {
|
||||
Log.d(TAG, "using an intent with action ${intent.action}")
|
||||
when (intent.action) {
|
||||
|
|
@ -90,6 +98,15 @@ class SubscriberService : Service() {
|
|||
Log.init(this) // Init logs in all entry points
|
||||
Log.d(TAG, "Subscriber service has been created")
|
||||
|
||||
initializeForegroundState()
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the foreground state by creating the notification channel and notification,
|
||||
* then calling startForeground(). This is called from onCreate() and as a safety fallback
|
||||
* from onStartCommand() if onCreate() didn't complete properly.
|
||||
*/
|
||||
private fun initializeForegroundState() {
|
||||
val title = getString(R.string.channel_subscriber_notification_title)
|
||||
val text = if (BuildConfig.FIREBASE_AVAILABLE) {
|
||||
getString(R.string.channel_subscriber_notification_instant_text)
|
||||
|
|
@ -113,9 +130,10 @@ class SubscriberService : Service() {
|
|||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && e is ForegroundServiceStartNotAllowedException) {
|
||||
Log.w(TAG, "Cannot start foreground service from background, stopping: ${e.message}")
|
||||
stopSelf()
|
||||
return
|
||||
} else {
|
||||
throw e
|
||||
Log.w(TAG, "Failed to start foreground: ${e.message}")
|
||||
// Don't rethrow: let the service continue and hope for the best,
|
||||
// or Android will kill it. Either way, we don't crash the app (see #1520).
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -134,7 +152,6 @@ class SubscriberService : Service() {
|
|||
}
|
||||
Log.d(TAG, "Starting the foreground service task")
|
||||
isServiceStarted = true
|
||||
saveServiceState(this, ServiceState.STARTED)
|
||||
wakeLock = (getSystemService(POWER_SERVICE) as PowerManager).run {
|
||||
newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG)
|
||||
}
|
||||
|
|
@ -164,7 +181,6 @@ class SubscriberService : Service() {
|
|||
}
|
||||
|
||||
isServiceStarted = false
|
||||
saveServiceState(this, ServiceState.STOPPED)
|
||||
}
|
||||
|
||||
private fun refreshConnections() {
|
||||
|
|
@ -238,7 +254,7 @@ class SubscriberService : Service() {
|
|||
}
|
||||
|
||||
// Update foreground service notification popup
|
||||
if (connections.size > 0) {
|
||||
if (connections.isNotEmpty()) {
|
||||
val title = getString(R.string.channel_subscriber_notification_title)
|
||||
val text = if (BuildConfig.FIREBASE_AVAILABLE) {
|
||||
when (instantSubscriptions.size) {
|
||||
|
|
@ -357,11 +373,6 @@ class SubscriberService : Service() {
|
|||
STOP
|
||||
}
|
||||
|
||||
enum class ServiceState {
|
||||
STARTED,
|
||||
STOPPED,
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "NtfySubscriberService"
|
||||
const val SERVICE_START_WORKER_VERSION = BuildConfig.VERSION_CODE
|
||||
|
|
@ -372,20 +383,5 @@ class SubscriberService : Service() {
|
|||
private const val NOTIFICATION_GROUP_ID = "io.heckel.ntfy.NOTIFICATION_GROUP_SERVICE"
|
||||
private const val NOTIFICATION_SERVICE_ID = 2586
|
||||
private const val NOTIFICATION_RECEIVED_WAKELOCK_TIMEOUT_MILLIS = 10*60*1000L /*10 minutes*/
|
||||
private const val SHARED_PREFS_ID = "SubscriberService"
|
||||
private const val SHARED_PREFS_SERVICE_STATE = "ServiceState"
|
||||
|
||||
fun saveServiceState(context: Context, state: ServiceState) {
|
||||
val sharedPrefs = context.getSharedPreferences(SHARED_PREFS_ID, MODE_PRIVATE)
|
||||
sharedPrefs.edit {
|
||||
putString(SHARED_PREFS_SERVICE_STATE, state.name)
|
||||
}
|
||||
}
|
||||
|
||||
fun readServiceState(context: Context): ServiceState {
|
||||
val sharedPrefs = context.getSharedPreferences(SHARED_PREFS_ID, MODE_PRIVATE)
|
||||
val value = sharedPrefs.getString(SHARED_PREFS_SERVICE_STATE, ServiceState.STOPPED.name)
|
||||
return ServiceState.valueOf(value!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,14 @@ class SubscriberServiceManager(private val context: Context) {
|
|||
Log.d(TAG, "ServiceStartWorker: Starting foreground service (work ID: ${id})")
|
||||
Intent(context, SubscriberService::class.java).also {
|
||||
it.action = SubscriberService.Action.START.name
|
||||
ContextCompat.startForegroundService(context, it)
|
||||
try {
|
||||
ContextCompat.startForegroundService(context, it)
|
||||
} catch (e: Exception) {
|
||||
// ForegroundServiceDidNotStartInTimeException or other exceptions can occur
|
||||
// due to race conditions or system constraints. We log and continue;
|
||||
// the service will be retried on the next refresh() call.
|
||||
Log.w(TAG, "ServiceStartWorker: Failed to start foreground service: ${e.message}")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No instant subscriptions, stop the service using stopService()
|
||||
|
|
|
|||
|
|
@ -400,4 +400,19 @@
|
|||
<string name="settings_advanced_custom_headers_prefs_header_add">Добавяне на заглавка</string>
|
||||
<string name="settings_advanced_custom_headers_prefs_header_add_title">Добавяне на заглавка за сървъра</string>
|
||||
<string name="settings_advanced_custom_headers_prefs_header_add_summary">Заглавките ще бъдат изпращани с всяка заявка по HTTP. Всеки сървър може да има свой набор от заявки.</string>
|
||||
<string name="user_dialog_base_url_error_authorization_header_exists">Не може да бъде добавен потребител ако за сървъра е зададена потребителска заглавка Authorization</string>
|
||||
<string name="custom_headers_dialog_title_add">Добавяна на заглавка по избор</string>
|
||||
<string name="custom_headers_dialog_title_edit">Променяне на заглавка по избор</string>
|
||||
<string name="custom_headers_dialog_base_url_hint">Адрес на услугата</string>
|
||||
<string name="custom_headers_dialog_name_hint">Име на заглавката (напр. CF-Access-Client-Id)</string>
|
||||
<string name="custom_headers_dialog_value_hint">Стойност на заглавката (напр. 9f3c2e4a1b2d4e)</string>
|
||||
<string name="custom_headers_dialog_description_add">Добавяне на заглавка на HTTP по избор, която да бъде изпращана с всяка заявка към избрания сървър.</string>
|
||||
<string name="custom_headers_dialog_description_edit">Можете да променяте името и стойността на заглавката или да я премахнете.</string>
|
||||
<string name="custom_headers_dialog_error_invalid_name">Името на заглавката съдържа неприемливи знаци</string>
|
||||
<string name="custom_headers_dialog_error_reserved_name">Тази заглавка е запазена и се задава от ntfy</string>
|
||||
<string name="custom_headers_dialog_error_user_exists">Не може да бъде добавена заглавка Authorization ако за сървъра е зададен потребител</string>
|
||||
<string name="custom_headers_dialog_error_duplicate">Заглавка с това име вече има за този сървър</string>
|
||||
<string name="custom_headers_dialog_button_add">Добавяне</string>
|
||||
<string name="custom_headers_dialog_button_save">Запазване</string>
|
||||
<string name="custom_headers_dialog_button_delete">Премахване</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -349,4 +349,70 @@
|
|||
<string name="settings_general_dynamic_colors_title">動態色彩</string>
|
||||
<string name="settings_general_dynamic_colors_summary_enabled">使用系統動態色彩</string>
|
||||
<string name="settings_general_dynamic_colors_summary_disabled">使用 ntfy 主題色彩</string>
|
||||
<string name="publish_dialog_title">發佈至 %1$s</string>
|
||||
<string name="publish_dialog_title_hint">標題</string>
|
||||
<string name="publish_dialog_title_placeholder">例如:有人在門口</string>
|
||||
<string name="publish_dialog_message_hint">訊息</string>
|
||||
<string name="publish_dialog_tags_hint">標籤</string>
|
||||
<string name="publish_dialog_tags_placeholder">例如:warning、skull</string>
|
||||
<string name="publish_dialog_priority_hint">優先順序</string>
|
||||
<string name="publish_dialog_button_publish">發佈</string>
|
||||
<string name="publish_dialog_error_sending">無法發佈訊息:%1$s</string>
|
||||
<string name="publish_dialog_error_server">無法發佈訊息:%1$s(代碼 %2$d)</string>
|
||||
<string name="publish_dialog_message_published">訊息已發佈</string>
|
||||
<string name="publish_dialog_uploading">上傳中:%1$s(%2$s / %3$s)</string>
|
||||
<string name="publish_dialog_upload_cancelled">上傳已取消</string>
|
||||
<string name="publish_dialog_chip_title">標題</string>
|
||||
<string name="publish_dialog_chip_tags">標籤</string>
|
||||
<string name="publish_dialog_chip_priority">優先順序</string>
|
||||
<string name="publish_dialog_chip_click_url">點擊網址</string>
|
||||
<string name="publish_dialog_chip_email">電子郵件</string>
|
||||
<string name="publish_dialog_chip_delay">延遲</string>
|
||||
<string name="publish_dialog_chip_markdown">Markdown</string>
|
||||
<string name="publish_dialog_chip_attach_url">透過網址附加</string>
|
||||
<string name="publish_dialog_chip_attach_file">附加本機檔案</string>
|
||||
<string name="publish_dialog_chip_phone_call">電話撥打</string>
|
||||
<string name="publish_dialog_click_url_hint">點擊網址</string>
|
||||
<string name="publish_dialog_click_url_placeholder">例如:https://example.com/alerts/1234</string>
|
||||
<string name="publish_dialog_email_hint">電子郵件</string>
|
||||
<string name="publish_dialog_email_placeholder">例如:phil@example.com</string>
|
||||
<string name="publish_dialog_delay_hint">延遲傳送</string>
|
||||
<string name="publish_dialog_delay_placeholder">例如:30m、1h、today 9pm(僅支援英文)</string>
|
||||
<string name="publish_dialog_attach_url_hint">附件網址</string>
|
||||
<string name="publish_dialog_attach_url_placeholder">例如:https://example.com/flowers.jpg</string>
|
||||
<string name="publish_dialog_attach_filename_hint">附件檔名</string>
|
||||
<string name="publish_dialog_attach_filename_placeholder">例如:lilies.jpg</string>
|
||||
<string name="publish_dialog_phone_call_hint">電話撥打</string>
|
||||
<string name="publish_dialog_phone_call_placeholder">例如:+1234567890</string>
|
||||
<string name="message_bar_hint">在此輸入訊息</string>
|
||||
<string name="message_bar_publish_button_description">發佈訊息</string>
|
||||
<string name="message_bar_expand_button_description">更多選項</string>
|
||||
<string name="detail_fab_publish_description">發佈通知</string>
|
||||
<string name="settings_general_language_title">語言</string>
|
||||
<string name="settings_general_language_summary_system">使用系統預設</string>
|
||||
<string name="settings_general_language_system_default">系統預設</string>
|
||||
<string name="settings_general_message_bar_title">顯示訊息列</string>
|
||||
<string name="settings_general_message_bar_summary_enabled">在主題檢視底部顯示訊息列</string>
|
||||
<string name="settings_general_message_bar_summary_disabled">在主題檢視底部顯示發佈按鈕</string>
|
||||
<string name="settings_advanced_custom_headers_title">自訂標頭</string>
|
||||
<string name="settings_advanced_custom_headers_summary">定義隨每次請求一併傳送的自訂 HTTP 標頭,例如當你的 ntfy 伺服器位於需要驗證的代理或通道之後。</string>
|
||||
<string name="settings_advanced_custom_headers_prefs_header_add">新增標頭</string>
|
||||
<string name="settings_advanced_custom_headers_prefs_header_add_title">為伺服器新增標頭</string>
|
||||
<string name="settings_advanced_custom_headers_prefs_header_add_summary">標頭會隨每次 HTTP 請求一併傳送。每個 ntfy 伺服器都可以有自己的一組自訂標頭。</string>
|
||||
<string name="user_dialog_base_url_error_authorization_header_exists">若此伺服器已設定自訂 Authorization 標頭,則無法新增使用者</string>
|
||||
<string name="custom_headers_dialog_title_add">新增自訂標頭</string>
|
||||
<string name="custom_headers_dialog_title_edit">編輯自訂標頭</string>
|
||||
<string name="custom_headers_dialog_base_url_hint">服務網址</string>
|
||||
<string name="custom_headers_dialog_name_hint">標頭名稱(例如:CF-Access-Client-Id)</string>
|
||||
<string name="custom_headers_dialog_value_hint">標頭值(例如:9f3c2e4a1b2d4e)</string>
|
||||
<string name="custom_headers_dialog_description_add">新增一個會隨每次請求傳送至指定伺服器的自訂 HTTP 標頭。</string>
|
||||
<string name="custom_headers_dialog_description_edit">你可以編輯所選標頭的名稱或值,或將其刪除。</string>
|
||||
<string name="custom_headers_dialog_error_invalid_name">標頭名稱包含無效字元</string>
|
||||
<string name="custom_headers_dialog_error_reserved_name">此標頭為保留項目,並由 ntfy 設定</string>
|
||||
<string name="custom_headers_dialog_error_user_exists">若此伺服器已設定使用者,則無法新增 Authorization 標頭</string>
|
||||
<string name="custom_headers_dialog_error_duplicate">此伺服器已存在相同名稱的標頭</string>
|
||||
<string name="custom_headers_dialog_button_add">新增</string>
|
||||
<string name="custom_headers_dialog_button_save">儲存</string>
|
||||
<string name="custom_headers_dialog_button_delete">刪除</string>
|
||||
<string name="publish_dialog_docs_text">如需範例與所有發佈功能的詳細說明,請參考 <a href="https://docs.ntfy.sh/publish/">說明文件</a>。</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -10,3 +10,4 @@ Maintenance + bug fixes:
|
|||
* Add support for (technically incorrect) 'image/jpg' MIME type (ntfy-android#142, thanks to @Murilobeluco)
|
||||
* Unify "copy to clipboard" notifications, use Android 13 style (ntfy-android#61, thanks to @thgoebel)
|
||||
* Fix crash in user add dialog (onAddUser)
|
||||
* Fix ForegroundServiceDidNotStartInTimeException (attempt 2, see #1520)
|
||||
Loading…
Add table
Reference in a new issue