Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions AnkiDroid/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,11 @@
/>
</receiver>

<!-- Copy Sync Error Message to Clipboard -->
<receiver
android:name="com.ichi2.anki.receiver.CopyToClipboardReceiver"
android:exported="false" />

<!-- "Add Note" widget -->
<receiver
android:name="com.ichi2.widget.AddNoteWidget"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2026 LUwUcifer <luwucifwer@proton.me>
*
* 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; either version 3 of the License, or (at your option) any later
* version.
*
* 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 <http://www.gnu.org/licenses/>.
*/
package com.ichi2.anki.receiver

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.core.app.NotificationManagerCompat
import com.ichi2.anki.notifications.NotificationId
import com.ichi2.utils.copyToClipboard
import timber.log.Timber

class CopyToClipboardReceiver : BroadcastReceiver() {
override fun onReceive(
context: Context,
intent: Intent,
) {
val text =
intent.getStringExtra(SYNC_ERROR_LOG) ?: run {
Timber.w("CopyToClipboardReceiver: no error log found")
return
}
NotificationManagerCompat.from(context).cancel(NotificationId.SYNC_MEDIA)
context.copyToClipboard(text)
}

companion object {
const val SYNC_ERROR_LOG = "COPY ERROR"
}
}
26 changes: 26 additions & 0 deletions AnkiDroid/src/main/java/com/ichi2/anki/worker/SyncMediaWorker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
package com.ichi2.anki.worker

import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
import android.os.Build
import androidx.core.app.NotificationCompat
Expand All @@ -40,6 +42,7 @@
import com.ichi2.anki.R
import com.ichi2.anki.cancelMediaSync
import com.ichi2.anki.notifications.NotificationId
import com.ichi2.anki.receiver.CopyToClipboardReceiver
import com.ichi2.anki.utils.ext.trySetForeground
import com.ichi2.utils.Permissions
import kotlinx.coroutines.CancellationException
Expand Down Expand Up @@ -94,6 +97,16 @@
setContentTitle(CollectionManager.TR.syncMediaFailed())
throwable.localizedMessage?.let { message ->
setContentText(message)
setStyle(
NotificationCompat
.BigTextStyle()
.bigText(message),
)
addAction(
R.drawable.baseline_content_copy_24,
CollectionManager.TR.qtMiscCopyToClipboard(),
getCopyToClipboardIntent(message),
)
}
}
Timber.d("SyncMediaWorker: showing failure notification")
Expand Down Expand Up @@ -145,7 +158,20 @@
}
}

private fun getCopyToClipboardIntent(text: String): PendingIntent {
val intent = Intent(applicationContext, CopyToClipboardReceiver::class.java)
intent.apply {
putExtra(CopyToClipboardReceiver.SYNC_ERROR_LOG, text)
}
return PendingIntent.getBroadcast(
applicationContext,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}

private fun notify(notification: Notification) = notificationManager?.notify(NotificationId.SYNC_MEDIA, notification)

Check failure

Code scanning / CodeQL

Use of implicit PendingIntents High

An implicit Intent is created
and sent to an unspecified third party through a PendingIntent.

private fun notify(builder: NotificationCompat.Builder.() -> Unit) {
notify(buildNotification(builder))
Expand Down
Loading