Merge branch 'dev_rescued'
This commit is contained in:
@@ -19,8 +19,8 @@ android {
|
||||
applicationId "xyz.quaver.pupil"
|
||||
minSdkVersion 16
|
||||
targetSdkVersion 29
|
||||
versionCode 48
|
||||
versionName "4.12"
|
||||
versionCode 49
|
||||
versionName "4.13"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
multiDexEnabled true
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
@@ -35,9 +35,6 @@ android {
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
release {
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
|
||||
buildConfigField('Boolean', 'CENSOR', 'false')
|
||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":48,"versionName":"4.12","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release","dirName":""},"path":"app-release.apk","properties":{}}]
|
||||
[{"outputType":{"type":"APK"},"apkData":{"type":"MAIN","splits":[],"versionCode":49,"versionName":"4.13","enabled":true,"outputFile":"app-release.apk","fullName":"release","baseName":"release","dirName":""},"path":"app-release.apk","properties":{}}]
|
||||
@@ -8,6 +8,7 @@
|
||||
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
|
||||
|
||||
<application
|
||||
@@ -20,7 +21,8 @@
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/AppTheme"
|
||||
tools:replace="android:theme"
|
||||
android:requestLegacyExternalStorage="true">
|
||||
android:requestLegacyExternalStorage="true"
|
||||
tools:ignore="UnusedAttribute">
|
||||
|
||||
<provider
|
||||
android:authorities="${applicationId}.provider"
|
||||
@@ -34,6 +36,12 @@
|
||||
|
||||
</provider>
|
||||
|
||||
<receiver android:name=".BroadcastReciever" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity android:name=".ui.LockActivity" />
|
||||
<activity
|
||||
android:name=".ui.ReaderActivity"
|
||||
|
||||
93
app/src/main/java/xyz/quaver/pupil/BroadcastReciever.kt
Normal file
93
app/src/main/java/xyz/quaver/pupil/BroadcastReciever.kt
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Pupil, Hitomi.la viewer for Android
|
||||
* Copyright (C) 2020 tom5079
|
||||
*
|
||||
* 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 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
@@ -341,7 +341,7 @@ class MainActivity : AppCompatActivity() {
|
||||
setImageResource(R.drawable.ic_jump)
|
||||
setOnClickListener {
|
||||
val preference = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
val perPage = preference.getString("per_page", "25")!!.toInt()
|
||||
val perPage = preference.getString("per_page", "25")!!.toIntOrNull() ?: 25
|
||||
val editText = EditText(context)
|
||||
|
||||
AlertDialog.Builder(context).apply {
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
@@ -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) { _, _ ->
|
||||
|
||||
@@ -132,4 +132,6 @@
|
||||
<string name="proxy_dialog_server">サーバー</string>
|
||||
<string name="main_menu_thin">簡単モード</string>
|
||||
<string name="main_fab_cancel">すべてのダウンロードキャンセル</string>
|
||||
<string name="channel_update">アップデート</string>
|
||||
<string name="channel_update_description">アップデートの進行状態を表示</string>
|
||||
</resources>
|
||||
@@ -132,4 +132,6 @@
|
||||
<string name="proxy_dialog_server">서버</string>
|
||||
<string name="main_menu_thin">간단히 보기 모드</string>
|
||||
<string name="main_fab_cancel">다운로드 모두 취소</string>
|
||||
<string name="channel_update">업데이트</string>
|
||||
<string name="channel_update_description">업데이트 진행상황 표시</string>
|
||||
</resources>
|
||||
@@ -35,6 +35,9 @@
|
||||
<string name="channel_download">Download</string>
|
||||
<string name="channel_download_description">Shows download status</string>
|
||||
|
||||
<string name="channel_update">Update</string>
|
||||
<string name="channel_update_description">Shows update progress</string>
|
||||
|
||||
<string name="unable_to_connect">Unable to connect to hitomi.la</string>
|
||||
|
||||
<string name="lock_corrupted">Lock file corrupted! Please re-install Pupil</string>
|
||||
|
||||
@@ -11,8 +11,6 @@ dependencies {
|
||||
testImplementation 'junit:junit:4.13'
|
||||
}
|
||||
|
||||
sourceCompatibility = "7"
|
||||
targetCompatibility = "7"
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
@@ -75,7 +75,7 @@ class UnitTest {
|
||||
|
||||
@Test
|
||||
fun test_getReader() {
|
||||
val reader = getReader(1567569)
|
||||
val reader = getReader(1574736)
|
||||
|
||||
print(reader)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user