diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d4685ef8..b61f152c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,7 +21,8 @@ android:supportsRtl="true" android:theme="@style/AppTheme" tools:replace="android:theme" - android:requestLegacyExternalStorage="true"> + android:requestLegacyExternalStorage="true" + tools:ignore="UnusedAttribute"> + + + + + + . + */ + +package xyz.quaver.pupil + +import android.app.DownloadManager +import android.app.PendingIntent +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.net.Uri +import android.webkit.MimeTypeMap +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat +import androidx.core.content.FileProvider +import androidx.preference.PreferenceManager +import xyz.quaver.pupil.util.NOTIFICATION_ID_UPDATE +import java.io.File + +class BroadcastReciever : BroadcastReceiver() { + + override fun onReceive(context: Context?, intent: Intent?) { + context ?: return + + when (intent?.action) { + DownloadManager.ACTION_DOWNLOAD_COMPLETE -> { + + // Validate download + + val preference = PreferenceManager.getDefaultSharedPreferences(context) + val downloadID = preference.getLong("update_download_id", -1) + val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager + + if (intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1) != downloadID) + return + + // Get target uri + + val query = DownloadManager.Query() + .setFilterById(downloadID) + + val uri = downloadManager.query(query).use { cursor -> + cursor.moveToFirst() + + cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI)).let { + val uri = Uri.parse(it) + + when (uri.scheme) { + "file" -> + FileProvider.getUriForFile(context, context.applicationContext.packageName + ".provider", File(uri.path!!)) + "content" -> uri + else -> return + } + } + } + + // Build Notification + + val notificationManager = NotificationManagerCompat.from(context) + + val pendingIntent = PendingIntent.getActivity(context, 0, Intent(Intent.ACTION_VIEW).apply { + flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK + setDataAndType(uri, MimeTypeMap.getSingleton().getMimeTypeFromExtension("apk")) + }, 0) + + val notification = NotificationCompat.Builder(context, "update") + .setSmallIcon(android.R.drawable.stat_sys_download_done) + .setContentTitle(context.getText(R.string.update_download_completed)) + .setContentText(context.getText(R.string.update_download_completed_description)) + .setContentIntent(pendingIntent) + .build() + + notificationManager.notify(NOTIFICATION_ID_UPDATE, notification) + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/Pupil.kt b/app/src/main/java/xyz/quaver/pupil/Pupil.kt index ff48c13e..9ec3d664 100644 --- a/app/src/main/java/xyz/quaver/pupil/Pupil.kt +++ b/app/src/main/java/xyz/quaver/pupil/Pupil.kt @@ -51,7 +51,10 @@ class Pupil : MultiDexApplication() { proxy = getProxy(this) try { - preference.getString("dl_location", null) + preference.getString("dl_location", null).also { + if (!File(it!!).canWrite()) + throw Exception() + } } catch (e: Exception) { preference.edit().remove("dl_location").apply() } @@ -72,13 +75,20 @@ class Pupil : MultiDexApplication() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - val channel = NotificationChannel("download", getString(R.string.channel_download), NotificationManager.IMPORTANCE_MIN).apply { + + manager.createNotificationChannel(NotificationChannel("download", getString(R.string.channel_download), NotificationManager.IMPORTANCE_LOW).apply { description = getString(R.string.channel_download_description) enableLights(false) enableVibration(false) lockscreenVisibility = Notification.VISIBILITY_SECRET - } - manager.createNotificationChannel(channel) + }) + + manager.createNotificationChannel(NotificationChannel("update", getString(R.string.channel_update), NotificationManager.IMPORTANCE_HIGH).apply { + description = getString(R.string.channel_update_description) + enableLights(true) + enableVibration(true) + lockscreenVisibility = Notification.VISIBILITY_SECRET + }) } AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) diff --git a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt index f4b97631..bc9de08a 100644 --- a/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt +++ b/app/src/main/java/xyz/quaver/pupil/ui/MainActivity.kt @@ -195,7 +195,7 @@ class MainActivity : AppCompatActivity() { override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { val preference = PreferenceManager.getDefaultSharedPreferences(this) - val perPage = preference.getString("per_page", "25")!!.toInt() + val perPage = preference.getString("per_page", "25")!!.toIntOrNull() ?: 25 val maxPage = ceil(totalItems / perPage.toDouble()).roundToInt() return when(keyCode) { @@ -369,14 +369,16 @@ class MainActivity : AppCompatActivity() { with(main_fab_id) { setImageResource(R.drawable.numeric) setOnClickListener { - val editText = EditText(context) + val editText = EditText(context).apply { + inputType = InputType.TYPE_CLASS_NUMBER + } AlertDialog.Builder(context).apply { setView(editText) setTitle(R.string.main_open_gallery_by_id) setPositiveButton(android.R.string.ok) { _, _ -> - val galleryID = editText.text.toString().toInt() + val galleryID = editText.text.toString().toIntOrNull() ?: return@setPositiveButton val intent = Intent(this@MainActivity, ReaderActivity::class.java).apply { putExtra("galleryID", galleryID) } diff --git a/app/src/main/java/xyz/quaver/pupil/util/ConstValues.kt b/app/src/main/java/xyz/quaver/pupil/util/ConstValues.kt index 38b24cf2..d70c8807 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/ConstValues.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/ConstValues.kt @@ -27,4 +27,6 @@ const val REQUEST_DOWNLOAD_FOLDER = 3874 const val REQUEST_DOWNLOAD_FOLDER_OLD = 3425 const val REQUEST_WRITE_PERMISSION_AND_SAF = 13900 +const val NOTIFICATION_ID_UPDATE = 2345 + val json = Json(JsonConfiguration.Stable) \ No newline at end of file diff --git a/app/src/main/java/xyz/quaver/pupil/util/update.kt b/app/src/main/java/xyz/quaver/pupil/util/update.kt index 94ae9ed1..7a687ba8 100644 --- a/app/src/main/java/xyz/quaver/pupil/util/update.kt +++ b/app/src/main/java/xyz/quaver/pupil/util/update.kt @@ -18,16 +18,10 @@ package xyz.quaver.pupil.util -import android.app.PendingIntent +import android.app.DownloadManager import android.content.Context -import android.content.Intent -import android.webkit.MimeTypeMap +import android.net.Uri import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatActivity -import androidx.core.app.NotificationCompat -import androidx.core.app.NotificationManagerCompat -import androidx.core.content.FileProvider -import androidx.lifecycle.Lifecycle import androidx.preference.PreferenceManager import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -81,7 +75,7 @@ fun getApkUrl(releases: JsonObject) : String? { } const val UPDATE_NOTIFICATION_ID = 384823 -fun checkUpdate(context: AppCompatActivity, force: Boolean = false) { +fun checkUpdate(context: Context, force: Boolean = false) { val preferences = PreferenceManager.getDefaultSharedPreferences(context) val ignoreUpdateUntil = preferences.getLong("ignore_update_until", 0) @@ -143,56 +137,27 @@ fun checkUpdate(context: AppCompatActivity, force: Boolean = false) { setMessage(Markwon.create(context).toMarkdown(msg)) setPositiveButton(android.R.string.yes) { _, _ -> - val notificationManager = NotificationManagerCompat.from(context) - val builder = NotificationCompat.Builder(context, "download").apply { - setContentTitle(context.getString(R.string.update_notification_description)) - setSmallIcon(android.R.drawable.stat_sys_download) - priority = NotificationCompat.PRIORITY_LOW - setOngoing(true) + val preference = PreferenceManager.getDefaultSharedPreferences(context) + + val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager + + //Cancel any download queued before + + val id = preference.getLong("update_download_id", -1) + + if (id != -1L) + downloadManager.remove(id) + + val target = File(context.getExternalFilesDir(null), "Pupil.apk").also { + it.delete() } - CoroutineScope(Dispatchers.IO).launch io@{ - val target = File(getDownloadDirectory(context), "Pupil.apk") + val request = DownloadManager.Request(Uri.parse(url)) + .setTitle(context.getText(R.string.update_notification_description)) + .setDestinationUri(Uri.fromFile(target)) - try { - URL(url).download(target) { progress, fileSize -> - builder.setProgress(fileSize.toInt(), progress.toInt(), false) - notificationManager.notify(UPDATE_NOTIFICATION_ID, builder.build()) - } - } catch (e: Exception) { - builder.apply { - setContentText(context.getString(R.string.update_failed)) - setMessage(context.getString(R.string.update_failed_message)) - setSmallIcon(android.R.drawable.stat_sys_download_done) - setOngoing(false) - } - - notificationManager.cancel(UPDATE_NOTIFICATION_ID) - notificationManager.notify(UPDATE_NOTIFICATION_ID, builder.build()) - - return@io - } - - val install = Intent(Intent.ACTION_VIEW).apply { - flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_GRANT_READ_URI_PERMISSION - setDataAndType(FileProvider.getUriForFile(context, context.applicationContext.packageName + ".provider", target), MimeTypeMap.getSingleton().getMimeTypeFromExtension("apk")) - } - - builder.apply { - setContentIntent(PendingIntent.getActivity(context, 0, install, 0)) - setProgress(0, 0, false) - setSmallIcon(android.R.drawable.stat_sys_download_done) - setContentTitle(context.getString(R.string.update_download_completed)) - setContentText(context.getString(R.string.update_download_completed_description)) - setOngoing(false) - } - - notificationManager.cancel(UPDATE_NOTIFICATION_ID) - - if (context.lifecycle.currentState.isAtLeast(Lifecycle.State.RESUMED)) - context.startActivity(install) - else - notificationManager.notify(UPDATE_NOTIFICATION_ID, builder.build()) + downloadManager.enqueue(request).also { + preference.edit().putLong("update_download_id", it).apply() } } setNegativeButton(if (force) android.R.string.no else R.string.ignore_update) { _, _ -> diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index f26ea3d7..9d764026 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -132,4 +132,6 @@ サーバー 簡単モード すべてのダウンロードキャンセル + アップデート + アップデートの進行状態を表示 \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 99ebfe1f..394dbff5 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -132,4 +132,6 @@ 서버 간단히 보기 모드 다운로드 모두 취소 + 업데이트 + 업데이트 진행상황 표시 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fd51625d..519bc5ae 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -35,6 +35,9 @@ Download Shows download status + Update + Shows update progress + Unable to connect to hitomi.la Lock file corrupted! Please re-install Pupil diff --git a/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt b/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt index 4d56ed56..bd3661a6 100644 --- a/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt +++ b/libpupil/src/test/java/xyz/quaver/hitomi/UnitTest.kt @@ -75,7 +75,7 @@ class UnitTest { @Test fun test_getReader() { - val reader = getReader(1567569) + val reader = getReader(1574736) print(reader) }