diff --git a/app/build.gradle b/app/build.gradle index b6c002771..6edad7fb7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,15 +8,14 @@ plugins { } android { - compileSdk = 33 -// compileSdkExtension = 4 + compileSdk = 34 buildToolsVersion = '34.0.0' namespace = 'org.koitharu.kotatsu' defaultConfig { applicationId 'org.koitharu.kotatsu' minSdkVersion 21 - targetSdkVersion 33 + targetSdkVersion 34 versionCode 570 versionName '6.0-a1' generatedDensities = [] diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bc598d4b7..ead6c4c9c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,6 +18,7 @@ + @@ -185,7 +186,13 @@ - + + diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Android.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Android.kt index 42cfcaab0..271e3a1a5 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Android.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Android.kt @@ -83,7 +83,7 @@ fun ActivityResultLauncher.tryLaunch( e.printStackTraceDebug() }.isSuccess -fun SharedPreferences.observe() = callbackFlow { +fun SharedPreferences.observe() = callbackFlow { val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> trySendBlocking(key) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsActivity.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsActivity.kt index fa22c000c..ca024aeae 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsActivity.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/list/DownloadsActivity.kt @@ -98,11 +98,11 @@ class DownloadsActivity : BaseActivity(), } override fun onPauseClick(item: DownloadItemModel) { - sendBroadcast(PausingReceiver.getPauseIntent(item.id)) + sendBroadcast(PausingReceiver.getPauseIntent(this, item.id)) } override fun onResumeClick(item: DownloadItemModel) { - sendBroadcast(PausingReceiver.getResumeIntent(item.id)) + sendBroadcast(PausingReceiver.getResumeIntent(this, item.id)) } override fun onSelectionChanged(controller: ListSelectionController, count: Int) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt index 7bba51708..131abe9a5 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/DownloadWorker.kt @@ -2,6 +2,8 @@ package org.koitharu.kotatsu.download.ui.worker import android.app.NotificationManager import android.content.Context +import android.content.pm.ServiceInfo +import android.os.Build import android.webkit.MimeTypeMap import androidx.core.content.ContextCompat import androidx.hilt.work.HiltWorker @@ -130,10 +132,18 @@ class DownloadWorker @AssistedInject constructor( } } - override suspend fun getForegroundInfo() = ForegroundInfo( - id.hashCode(), - notificationFactory.create(lastPublishedState), - ) + override suspend fun getForegroundInfo() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + ForegroundInfo( + id.hashCode(), + notificationFactory.create(lastPublishedState), + ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC, + ) + } else { + ForegroundInfo( + id.hashCode(), + notificationFactory.create(lastPublishedState), + ) + } private suspend fun downloadMangaImpl( includedIds: LongArray?, @@ -389,12 +399,12 @@ class DownloadWorker @AssistedInject constructor( } fun pause(id: UUID) { - val intent = PausingReceiver.getPauseIntent(id) + val intent = PausingReceiver.getPauseIntent(context, id) context.sendBroadcast(intent) } fun resume(id: UUID) { - val intent = PausingReceiver.getResumeIntent(id) + val intent = PausingReceiver.getResumeIntent(context, id) context.sendBroadcast(intent) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/PausingReceiver.kt b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/PausingReceiver.kt index 71dc7aa4c..8bf4298d0 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/PausingReceiver.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/download/ui/worker/PausingReceiver.kt @@ -40,18 +40,20 @@ class PausingReceiver( addDataPath(id.toString(), PatternMatcher.PATTERN_SIMPLE_GLOB) } - fun getPauseIntent(id: UUID) = Intent(ACTION_PAUSE) + fun getPauseIntent(context: Context, id: UUID) = Intent(ACTION_PAUSE) .setData(Uri.parse("$SCHEME://$id")) + .setPackage(context.packageName) .putExtra(EXTRA_UUID, id.toString()) - fun getResumeIntent(id: UUID) = Intent(ACTION_RESUME) + fun getResumeIntent(context: Context, id: UUID) = Intent(ACTION_RESUME) .setData(Uri.parse("$SCHEME://$id")) + .setPackage(context.packageName) .putExtra(EXTRA_UUID, id.toString()) fun createPausePendingIntent(context: Context, id: UUID) = PendingIntentCompat.getBroadcast( context, 0, - getPauseIntent(id), + getPauseIntent(context, id), 0, false, ) @@ -59,7 +61,7 @@ class PausingReceiver( fun createResumePendingIntent(context: Context, id: UUID) = PendingIntentCompat.getBroadcast( context, 0, - getResumeIntent(id), + getResumeIntent(context, id), 0, false, ) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/ImportWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/ImportWorker.kt index 5a4d600c3..e1e912caa 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/ImportWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/ui/ImportWorker.kt @@ -3,7 +3,9 @@ package org.koitharu.kotatsu.local.ui import android.app.Notification import android.app.PendingIntent import android.content.Context +import android.content.pm.ServiceInfo import android.net.Uri +import android.os.Build import androidx.core.app.NotificationChannelCompat import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat @@ -22,6 +24,7 @@ import coil.request.ImageRequest import dagger.assisted.Assisted import dagger.assisted.AssistedInject import org.koitharu.kotatsu.R +import org.koitharu.kotatsu.core.util.ext.checkNotificationPermission import org.koitharu.kotatsu.core.util.ext.getDisplayMessage import org.koitharu.kotatsu.core.util.ext.toBitmapOrNull import org.koitharu.kotatsu.core.util.ext.toUriOrNull @@ -46,7 +49,7 @@ class ImportWorker @AssistedInject constructor( val result = runCatchingCancellable { importer.import(uri).manga } - if (notificationManager.areNotificationsEnabled()) { + if (applicationContext.checkNotificationPermission()) { val notification = buildNotification(result) notificationManager.notify(uri.hashCode(), notification) } @@ -76,7 +79,11 @@ class ImportWorker @AssistedInject constructor( .setCategory(NotificationCompat.CATEGORY_PROGRESS) .build() - return ForegroundInfo(FOREGROUND_NOTIFICATION_ID, notification) + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + ForegroundInfo(FOREGROUND_NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC) + } else { + ForegroundInfo(FOREGROUND_NOTIFICATION_ID, notification) + } } private suspend fun buildNotification(result: kotlin.Result): Notification { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderInfoBarView.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderInfoBarView.kt index e0306c6fb..2f4e20047 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderInfoBarView.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/ReaderInfoBarView.kt @@ -13,16 +13,17 @@ import android.util.AttributeSet import android.view.View import android.view.WindowInsets import androidx.annotation.AttrRes +import androidx.core.content.ContextCompat import androidx.core.graphics.ColorUtils import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import org.koitharu.kotatsu.R import org.koitharu.kotatsu.core.util.ext.getThemeColor import org.koitharu.kotatsu.core.util.ext.measureDimension +import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.resolveDp import org.koitharu.kotatsu.parsers.util.format import org.koitharu.kotatsu.reader.ui.pager.ReaderUiState -import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import java.text.SimpleDateFormat import java.util.Date import com.google.android.material.R as materialR @@ -111,7 +112,12 @@ class ReaderInfoBarView @JvmOverloads constructor( override fun onAttachedToWindow() { super.onAttachedToWindow() - context.registerReceiver(timeReceiver, IntentFilter(Intent.ACTION_TIME_TICK)) + ContextCompat.registerReceiver( + context, + timeReceiver, + IntentFilter(Intent.ACTION_TIME_TICK), + ContextCompat.RECEIVER_EXPORTED, + ) updateCutoutInsets(ViewCompat.getRootWindowInsets(this)) } diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonScalingFrame.kt b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonScalingFrame.kt index bd1fe0fd5..a347ac35c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonScalingFrame.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/reader/ui/pager/webtoon/WebtoonScalingFrame.kt @@ -165,7 +165,8 @@ class WebtoonScalingFrame @JvmOverloads constructor( private inner class GestureListener : GestureDetector.SimpleOnGestureListener(), Runnable { - override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean { + + override fun onScroll(e1: MotionEvent?, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean { if (scale <= 1f) return false transformMatrix.postTranslate(-distanceX, -distanceY) invalidateTarget() @@ -185,7 +186,7 @@ class WebtoonScalingFrame @JvmOverloads constructor( return true } - override fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { + override fun onFling(e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean { if (scale <= 1) return false overScroller.fling( diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt index dc37f78ca..4b0ca53a4 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/suggestions/ui/SuggestionsWorker.kt @@ -2,6 +2,8 @@ package org.koitharu.kotatsu.suggestions.ui import android.app.PendingIntent import android.content.Context +import android.content.pm.ServiceInfo +import android.os.Build import androidx.annotation.FloatRange import androidx.core.app.NotificationChannelCompat import androidx.core.app.NotificationCompat @@ -120,7 +122,11 @@ class SuggestionsWorker @AssistedInject constructor( .setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_DEFERRED) .build() - return ForegroundInfo(WORKER_NOTIFICATION_ID, notification) + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + ForegroundInfo(WORKER_NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC) + } else { + ForegroundInfo(WORKER_NOTIFICATION_ID, notification) + } } private suspend fun doWorkImpl(): Int { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt index 50c6cf8be..06aa47101 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/tracker/work/TrackWorker.kt @@ -2,6 +2,7 @@ package org.koitharu.kotatsu.tracker.work import android.app.PendingIntent import android.content.Context +import android.content.pm.ServiceInfo import android.os.Build import androidx.core.app.NotificationChannelCompat import androidx.core.app.NotificationCompat @@ -258,7 +259,11 @@ class TrackWorker @AssistedInject constructor( .setSmallIcon(android.R.drawable.stat_notify_sync) .setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_DEFERRED) .build() - return ForegroundInfo(WORKER_NOTIFICATION_ID, notification) + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + ForegroundInfo(WORKER_NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC) + } else { + ForegroundInfo(WORKER_NOTIFICATION_ID, notification) + } } private suspend fun setRetryIds(ids: Set) = runInterruptible(Dispatchers.IO) {