mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-19 00:59:17 +01:00
Rewrote UpdateDownloader to Kotlin
Added auto update check (every 12 hour) Warning message optional fix #256 Lots of bug fixes!
This commit is contained in:
parent
ec9c19ce7d
commit
55e9d2880c
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="eu.kanade.tachiyomi"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="eu.kanade.tachiyomi">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
@ -68,7 +68,19 @@
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".data.library.LibraryUpdateService$LibraryUpdateReceiver">
|
||||
android:name=".data.library.LibraryUpdateService$SyncOnPowerConnected"
|
||||
android:enabled="false">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".data.library.LibraryUpdateService$CancelUpdateReceiver">
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".data.updater.UpdateDownloader$InstallOnReceived">
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
@ -79,6 +91,15 @@
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".data.updater.UpdateDownloaderAlarm">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
<action android:name="eu.kanade.CHECK_UPDATE"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
|
||||
<meta-data
|
||||
android:name="eu.kanade.tachiyomi.data.cache.CoverGlideModule"
|
||||
android:value="GlideModule" />
|
||||
|
@ -9,6 +9,8 @@ import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
import android.support.v4.app.NotificationCompat
|
||||
import android.util.Pair
|
||||
import com.github.pwittchen.reactivenetwork.library.ConnectivityStatus
|
||||
import com.github.pwittchen.reactivenetwork.library.ReactiveNetwork
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||
@ -16,42 +18,14 @@ import eu.kanade.tachiyomi.data.database.models.Manga
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.source.SourceManager
|
||||
import eu.kanade.tachiyomi.ui.main.MainActivity
|
||||
import eu.kanade.tachiyomi.util.AndroidComponentUtil
|
||||
import eu.kanade.tachiyomi.util.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.notification
|
||||
import eu.kanade.tachiyomi.util.notificationManager
|
||||
import eu.kanade.tachiyomi.util.*
|
||||
import rx.Observable
|
||||
import rx.Subscription
|
||||
import rx.schedulers.Schedulers
|
||||
import timber.log.Timber
|
||||
import java.util.*
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import javax.inject.Inject
|
||||
|
||||
// Intent key for forced library update
|
||||
val UPDATE_IS_FORCED = "is_forced"
|
||||
|
||||
/**
|
||||
* Get the start intent for [LibraryUpdateService].
|
||||
* @param context the application context.
|
||||
* @param isForced true when forcing library update
|
||||
* @return the intent of the service.
|
||||
*/
|
||||
fun getIntent(context: Context, isForced: Boolean = false): Intent {
|
||||
return Intent(context, LibraryUpdateService::class.java).apply {
|
||||
putExtra(UPDATE_IS_FORCED, isForced)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the service.
|
||||
* @param context the application context.
|
||||
* @return true if the service is running, false otherwise.
|
||||
*/
|
||||
fun isRunning(context: Context): Boolean {
|
||||
return AndroidComponentUtil.isServiceRunning(context, LibraryUpdateService::class.java)
|
||||
}
|
||||
|
||||
/**
|
||||
* This class will take care of updating the chapters of the manga from the library. It can be
|
||||
* started calling the [start] method. If it's already running, it won't do anything.
|
||||
@ -77,6 +51,30 @@ class LibraryUpdateService : Service() {
|
||||
companion object {
|
||||
val UPDATE_NOTIFICATION_ID = 1
|
||||
|
||||
// Intent key for manual library update
|
||||
val UPDATE_IS_MANUAL = "is_manual"
|
||||
|
||||
/**
|
||||
* Get the start intent for [LibraryUpdateService].
|
||||
* @param context the application context.
|
||||
* @param isManual true when user triggers library update.
|
||||
* @return the intent of the service.
|
||||
*/
|
||||
fun getIntent(context: Context, isManual: Boolean = false): Intent {
|
||||
return Intent(context, LibraryUpdateService::class.java).apply {
|
||||
putExtra(UPDATE_IS_MANUAL, isManual)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the status of the service.
|
||||
* @param context the application context.
|
||||
* @return true if the service is running, false otherwise.
|
||||
*/
|
||||
fun isRunning(context: Context): Boolean {
|
||||
return AndroidComponentUtil.isServiceRunning(context, LibraryUpdateService::class.java)
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method to start the service. It will be started only if there isn't another
|
||||
* instance already running.
|
||||
@ -125,36 +123,52 @@ class LibraryUpdateService : Service() {
|
||||
|
||||
|
||||
/**
|
||||
* Method called when the service receives an intent. In this case, the content of the intent
|
||||
* is irrelevant, because everything required is fetched in [updateLibrary].
|
||||
* @param intent the intent from [start].
|
||||
* Method called when the service receives an intent.
|
||||
* @param intent the start intent from.
|
||||
* @param flags the flags of the command.
|
||||
* @param startId the start id of this command.
|
||||
* @return the start value of the command.
|
||||
*/
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
// If there's no network available, set a component to start this service again when
|
||||
// a connection is available.
|
||||
if (!DeviceUtil.isNetworkConnected(this)) {
|
||||
Timber.i("Sync canceled, connection not available")
|
||||
showWarningNotification(getString(R.string.notification_no_connection_title),
|
||||
getString(R.string.notification_no_connection_body))
|
||||
|
||||
// Get connectivity status
|
||||
val connection = ReactiveNetwork().getConnectivityStatus(this, true)
|
||||
|
||||
// Get library update restrictions
|
||||
val restrictions = preferences.libraryUpdateRestriction()
|
||||
|
||||
// Check if users updates library manual
|
||||
val isManualUpdate = intent?.getBooleanExtra(UPDATE_IS_MANUAL, false) ?: false
|
||||
|
||||
// Whether to cancel the update.
|
||||
var cancelUpdate = false
|
||||
|
||||
// Check if device has internet connection
|
||||
// Check if device has wifi connection if only wifi is enabled
|
||||
if (connection == ConnectivityStatus.OFFLINE || ("wifi" in restrictions
|
||||
&& connection != ConnectivityStatus.WIFI_CONNECTED_HAS_INTERNET)) {
|
||||
|
||||
if (isManualUpdate) {
|
||||
toast(R.string.notification_no_connection_title)
|
||||
}
|
||||
|
||||
// Enable library update when connection available
|
||||
AndroidComponentUtil.toggleComponent(this, SyncOnConnectionAvailable::class.java, true)
|
||||
cancelUpdate = true
|
||||
}
|
||||
if (!isManualUpdate && "ac" in restrictions && !DeviceUtil.isPowerConnected(this)) {
|
||||
AndroidComponentUtil.toggleComponent(this, SyncOnPowerConnected::class.java, true)
|
||||
cancelUpdate = true
|
||||
}
|
||||
|
||||
if (cancelUpdate) {
|
||||
stopSelf(startId)
|
||||
return Service.START_NOT_STICKY
|
||||
}
|
||||
|
||||
// If user doesn't want to update while phone is not charging, cancel sync
|
||||
else if (preferences.updateOnlyWhenCharging() && !(intent?.getBooleanExtra(UPDATE_IS_FORCED, false) ?: false) && !DeviceUtil.isPowerConnected(this)) {
|
||||
Timber.i("Sync canceled, not connected to ac power")
|
||||
// Create force library update intent
|
||||
val forceIntent = getLibraryUpdateReceiverIntent(LibraryUpdateReceiver.FORCE_LIBRARY_UPDATE)
|
||||
// Show warning
|
||||
showWarningNotification(getString(R.string.notification_not_connected_to_ac_title),
|
||||
getString(R.string.notification_not_connected_to_ac_body), forceIntent)
|
||||
stopSelf(startId)
|
||||
return Service.START_NOT_STICKY
|
||||
}
|
||||
// Stop enabled components.
|
||||
AndroidComponentUtil.toggleComponent(this, SyncOnConnectionAvailable::class.java, false)
|
||||
AndroidComponentUtil.toggleComponent(this, SyncOnPowerConnected::class.java, false)
|
||||
|
||||
// Unsubscribe from any previous subscription if needed.
|
||||
subscription?.unsubscribe()
|
||||
@ -168,20 +182,11 @@ class LibraryUpdateService : Service() {
|
||||
stopSelf(startId)
|
||||
}, {
|
||||
stopSelf(startId)
|
||||
})
|
||||
})
|
||||
|
||||
return Service.START_STICKY
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PendingIntent for LibraryUpdate broadcast class
|
||||
* @param action id of action
|
||||
*/
|
||||
fun getLibraryUpdateReceiverIntent(action: String): PendingIntent {
|
||||
return PendingIntent.getBroadcast(this, 0,
|
||||
Intent(this, LibraryUpdateReceiver::class.java).apply { this.action = action }, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Method that updates the library. It's called in a background thread, so it's safe to do
|
||||
* heavy operations or network calls here.
|
||||
@ -195,7 +200,8 @@ class LibraryUpdateService : Service() {
|
||||
val newUpdates = ArrayList<Manga>()
|
||||
val failedUpdates = ArrayList<Manga>()
|
||||
|
||||
val cancelIntent = getLibraryUpdateReceiverIntent(LibraryUpdateReceiver.CANCEL_LIBRARY_UPDATE)
|
||||
val cancelIntent = PendingIntent.getBroadcast(this, 0,
|
||||
Intent(this, CancelUpdateReceiver::class.java), 0)
|
||||
|
||||
// Get the manga list that is going to be updated.
|
||||
val allLibraryMangas = db.getFavoriteMangas().executeAsBlocking()
|
||||
@ -299,12 +305,11 @@ class LibraryUpdateService : Service() {
|
||||
* @param body the body of the notification.
|
||||
*/
|
||||
private fun showNotification(title: String, body: String) {
|
||||
val n = notification() {
|
||||
notificationManager.notify(UPDATE_NOTIFICATION_ID, notification() {
|
||||
setSmallIcon(R.drawable.ic_refresh_white_24dp_img)
|
||||
setContentTitle(title)
|
||||
setContentText(body)
|
||||
}
|
||||
notificationManager.notify(UPDATE_NOTIFICATION_ID, n)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -314,35 +319,15 @@ class LibraryUpdateService : Service() {
|
||||
* @param total the total progress.
|
||||
*/
|
||||
private fun showProgressNotification(manga: Manga, current: Int, total: Int, cancelIntent: PendingIntent) {
|
||||
val n = notification() {
|
||||
notificationManager.notify(UPDATE_NOTIFICATION_ID, notification() {
|
||||
setSmallIcon(R.drawable.ic_refresh_white_24dp_img)
|
||||
setContentTitle(manga.title)
|
||||
setProgress(total, current, false)
|
||||
setOngoing(true)
|
||||
addAction(R.drawable.ic_clear_grey_24dp_img, getString(android.R.string.cancel), cancelIntent)
|
||||
}
|
||||
notificationManager.notify(UPDATE_NOTIFICATION_ID, n)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Show warning message when library can't be updated
|
||||
* @param warningTitle title of warning
|
||||
* @param warningBody warning information
|
||||
* @param pendingIntent Intent called when action clicked
|
||||
*/
|
||||
private fun showWarningNotification(warningTitle: String, warningBody: String, pendingIntent: PendingIntent? = null) {
|
||||
val n = notification() {
|
||||
setSmallIcon(R.drawable.ic_warning_white_24dp_img)
|
||||
setContentTitle(warningTitle)
|
||||
setStyle(NotificationCompat.BigTextStyle().bigText(warningBody))
|
||||
setContentIntent(notificationIntent)
|
||||
if (pendingIntent != null) {
|
||||
addAction(R.drawable.ic_refresh_grey_24dp_img, getString(R.string.action_force), pendingIntent)
|
||||
}
|
||||
setAutoCancel(true)
|
||||
}
|
||||
notificationManager.notify(UPDATE_NOTIFICATION_ID, n)
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the notification containing the result of the update done by the service.
|
||||
@ -353,14 +338,13 @@ class LibraryUpdateService : Service() {
|
||||
val title = getString(R.string.notification_update_completed)
|
||||
val body = getUpdatedMangasBody(updates, failed)
|
||||
|
||||
val n = notification() {
|
||||
notificationManager.notify(UPDATE_NOTIFICATION_ID, notification() {
|
||||
setSmallIcon(R.drawable.ic_refresh_white_24dp_img)
|
||||
setContentTitle(title)
|
||||
setStyle(NotificationCompat.BigTextStyle().bigText(body))
|
||||
setContentIntent(notificationIntent)
|
||||
setAutoCancel(true)
|
||||
}
|
||||
notificationManager.notify(UPDATE_NOTIFICATION_ID, n)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@ -385,7 +369,6 @@ class LibraryUpdateService : Service() {
|
||||
* network changes.
|
||||
*/
|
||||
class SyncOnConnectionAvailable : BroadcastReceiver() {
|
||||
|
||||
/**
|
||||
* Method called when a network change occurs.
|
||||
* @param context the application context.
|
||||
@ -394,35 +377,38 @@ class LibraryUpdateService : Service() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (DeviceUtil.isNetworkConnected(context)) {
|
||||
AndroidComponentUtil.toggleComponent(context, this.javaClass, false)
|
||||
context.startService(getIntent(context))
|
||||
start(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that triggers the library to update.
|
||||
* Class that triggers the library to update when connected to power.
|
||||
*/
|
||||
class LibraryUpdateReceiver : BroadcastReceiver() {
|
||||
companion object {
|
||||
// Cancel library update action
|
||||
val CANCEL_LIBRARY_UPDATE = "eu.kanade.CANCEL_LIBRARY_UPDATE"
|
||||
// Force library update
|
||||
val FORCE_LIBRARY_UPDATE = "eu.kanade.FORCE_LIBRARY_UPDATE"
|
||||
class SyncOnPowerConnected: BroadcastReceiver() {
|
||||
/**
|
||||
* Method called when AC is connected.
|
||||
* @param context the application context.
|
||||
* @param intent the intent received.
|
||||
*/
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
AndroidComponentUtil.toggleComponent(context, this.javaClass, false)
|
||||
start(context)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class that stops updating the library.
|
||||
*/
|
||||
class CancelUpdateReceiver : BroadcastReceiver() {
|
||||
/**
|
||||
* Method called when user wants a library update.
|
||||
* @param context the application context.
|
||||
* @param intent the intent received.
|
||||
*/
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
when (intent.action) {
|
||||
CANCEL_LIBRARY_UPDATE -> {
|
||||
LibraryUpdateService.stop(context)
|
||||
context.notificationManager.cancel(UPDATE_NOTIFICATION_ID)
|
||||
}
|
||||
FORCE_LIBRARY_UPDATE -> LibraryUpdateService.start(context, true)
|
||||
}
|
||||
LibraryUpdateService.stop(context)
|
||||
context.notificationManager.cancel(UPDATE_NOTIFICATION_ID)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,16 +70,17 @@ class PreferenceKeys(context: Context) {
|
||||
|
||||
val removeAfterMarkedAsRead = context.getString(R.string.pref_remove_after_marked_as_read_key)
|
||||
|
||||
val updateOnlyWhenCharging = context.getString(R.string.pref_update_only_when_charging_key)
|
||||
|
||||
val libraryUpdateInterval = context.getString(R.string.pref_library_update_interval_key)
|
||||
|
||||
val libraryUpdateRestriction = context.getString(R.string.pref_library_update_restriction_key)
|
||||
|
||||
val filterDownloaded = context.getString(R.string.pref_filter_downloaded_key)
|
||||
|
||||
val filterUnread = context.getString(R.string.pref_filter_unread_key)
|
||||
|
||||
fun sourceUsername(sourceId: Int) = "pref_source_username_$sourceId"
|
||||
|
||||
|
||||
fun sourcePassword(sourceId: Int) = "pref_source_password_$sourceId"
|
||||
|
||||
fun syncUsername(syncId: Int) = "pref_mangasync_username_$syncId"
|
||||
|
@ -39,6 +39,11 @@ class PreferencesHelper(private val context: Context) {
|
||||
context.getString(R.string.pref_library_update_interval_key), 0)
|
||||
}
|
||||
|
||||
fun getAutomaticUpdateStatus(context: Context): Boolean {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
|
||||
context.getString(R.string.pref_enable_automatic_updates), false)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getTheme(context: Context): Int {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context).getInt(
|
||||
@ -132,10 +137,10 @@ class PreferencesHelper(private val context: Context) {
|
||||
|
||||
fun removeAfterMarkedAsRead() = prefs.getBoolean(keys.removeAfterMarkedAsRead, false)
|
||||
|
||||
fun updateOnlyWhenCharging() = prefs.getBoolean(keys.updateOnlyWhenCharging, false)
|
||||
|
||||
fun libraryUpdateInterval() = rxPrefs.getInteger(keys.libraryUpdateInterval, 0)
|
||||
|
||||
fun libraryUpdateRestriction() = prefs.getStringSet(keys.libraryUpdateRestriction, emptySet())
|
||||
|
||||
fun filterDownloaded() = rxPrefs.getBoolean(keys.filterDownloaded, false)
|
||||
|
||||
fun filterUnread() = rxPrefs.getBoolean(keys.filterUnread, false)
|
||||
|
@ -1,99 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.updater;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import eu.kanade.tachiyomi.App;
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper;
|
||||
|
||||
public class UpdateDownloader extends AsyncTask<String, Void, Void> {
|
||||
/**
|
||||
* Name of cache directory.
|
||||
*/
|
||||
private static final String PARAMETER_CACHE_DIRECTORY = "apk_downloads";
|
||||
/**
|
||||
* Interface to global information about an application environment.
|
||||
*/
|
||||
private final Context context;
|
||||
/**
|
||||
* Cache directory used for cache management.
|
||||
*/
|
||||
private final File cacheDir;
|
||||
@Inject PreferencesHelper preferencesHelper;
|
||||
|
||||
/**
|
||||
* Constructor of UpdaterCache.
|
||||
*
|
||||
* @param context application environment interface.
|
||||
*/
|
||||
public UpdateDownloader(Context context) {
|
||||
App.get(context).getComponent().inject(this);
|
||||
this.context = context;
|
||||
|
||||
// Get cache directory from parameter.
|
||||
cacheDir = new File(preferencesHelper.downloadsDirectory().get(), PARAMETER_CACHE_DIRECTORY);
|
||||
|
||||
// Create cache directory.
|
||||
createCacheDir();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create cache directory if it doesn't exist
|
||||
*
|
||||
* @return true if cache dir is created otherwise false.
|
||||
*/
|
||||
@SuppressWarnings("UnusedReturnValue")
|
||||
private boolean createCacheDir() {
|
||||
return !cacheDir.exists() && cacheDir.mkdirs();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(String... args) {
|
||||
try {
|
||||
createCacheDir();
|
||||
|
||||
URL url = new URL(args[0]);
|
||||
HttpURLConnection c = (HttpURLConnection) url.openConnection();
|
||||
c.connect();
|
||||
|
||||
File outputFile = new File(cacheDir, "update.apk");
|
||||
if (outputFile.exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
outputFile.delete();
|
||||
}
|
||||
FileOutputStream fos = new FileOutputStream(outputFile);
|
||||
|
||||
InputStream is = c.getInputStream();
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int len1;
|
||||
while ((len1 = is.read(buffer)) != -1) {
|
||||
fos.write(buffer, 0, len1);
|
||||
}
|
||||
fos.close();
|
||||
is.close();
|
||||
|
||||
// Prompt install interface
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setDataAndType(Uri.fromFile(outputFile), "application/vnd.android.package-archive");
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // without this flag android returned a intent error!
|
||||
context.startActivity(intent);
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,199 @@
|
||||
package eu.kanade.tachiyomi.data.updater
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.support.v4.app.NotificationCompat
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.data.network.ProgressListener
|
||||
import eu.kanade.tachiyomi.data.network.get
|
||||
import eu.kanade.tachiyomi.util.notificationManager
|
||||
import eu.kanade.tachiyomi.util.saveTo
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
class UpdateDownloader(private val context: Context) :
|
||||
AsyncTask<String, Int, UpdateDownloader.DownloadResult>() {
|
||||
|
||||
companion object {
|
||||
/**
|
||||
* Prompt user with apk install intent
|
||||
* @param context context
|
||||
* @param file file of apk that is installed
|
||||
*/
|
||||
fun installAPK(context: Context, file: File) {
|
||||
// Prompt install interface
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive")
|
||||
// Without this flag android returned a intent error!
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
@Inject lateinit var network: NetworkHelper
|
||||
|
||||
/**
|
||||
* Default download dir
|
||||
*/
|
||||
val apkFile = File(context.externalCacheDir, "update.apk")
|
||||
|
||||
|
||||
/**
|
||||
* Notification builder
|
||||
*/
|
||||
val notificationBuilder = NotificationCompat.Builder(context)
|
||||
|
||||
init {
|
||||
App.get(context).component.inject(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Class containing download result
|
||||
* @param url url of file
|
||||
* @param successful status of download
|
||||
*/
|
||||
class DownloadResult(var url: String, var successful: Boolean)
|
||||
|
||||
/**
|
||||
* Called before downloading
|
||||
*/
|
||||
override fun onPreExecute() {
|
||||
// Create download notification
|
||||
with(notificationBuilder) {
|
||||
setContentTitle(context.getString(R.string.update_check_notification_file_download))
|
||||
setContentText(context.getString(R.string.update_check_notification_download_in_progress))
|
||||
setSmallIcon(android.R.drawable.stat_sys_download)
|
||||
}
|
||||
}
|
||||
|
||||
override fun doInBackground(vararg params: String?): DownloadResult {
|
||||
// Initialize information array containing path and url to file.
|
||||
val result = DownloadResult(params[0]!!, false)
|
||||
|
||||
// Progress of the download
|
||||
var savedProgress = 0
|
||||
|
||||
val progressListener = object : ProgressListener {
|
||||
override fun update(bytesRead: Long, contentLength: Long, done: Boolean) {
|
||||
val progress = (100 * bytesRead / contentLength).toInt()
|
||||
if (progress > savedProgress) {
|
||||
savedProgress = progress
|
||||
publishProgress(progress)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Make the request and download the file
|
||||
val response = network.requestBodyProgressBlocking(get(result.url), progressListener)
|
||||
|
||||
if (response.isSuccessful) {
|
||||
response.body().source().saveTo(apkFile)
|
||||
// Set download successful
|
||||
result.successful = true
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Timber.e(e, e.message)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when progress is updated
|
||||
* @param values values containing progress
|
||||
*/
|
||||
override fun onProgressUpdate(vararg values: Int?) {
|
||||
// Notify notification manager to update notification
|
||||
values.getOrNull(0)?.let {
|
||||
notificationBuilder.setProgress(100, it, false)
|
||||
// Displays the progress bar on notification
|
||||
context.notificationManager.notify(InstallOnReceived.notificationId, notificationBuilder.build())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when download done
|
||||
* @param result string containing download information
|
||||
*/
|
||||
override fun onPostExecute(result: DownloadResult) {
|
||||
with(notificationBuilder) {
|
||||
if (result.successful) {
|
||||
setContentTitle(context.getString(R.string.app_name))
|
||||
setContentText(context.getString(R.string.update_check_notification_download_complete))
|
||||
addAction(R.drawable.ic_system_update_grey_24dp_img, context.getString(R.string.action_install),
|
||||
getInstallOnReceivedIntent(InstallOnReceived.INSTALL_APK, apkFile.absolutePath))
|
||||
addAction(R.drawable.ic_clear_grey_24dp_img, context.getString(R.string.action_cancel),
|
||||
getInstallOnReceivedIntent(InstallOnReceived.CANCEL_NOTIFICATION))
|
||||
} else {
|
||||
setContentText(context.getString(R.string.update_check_notification_download_error))
|
||||
addAction(R.drawable.ic_refresh_grey_24dp_img, context.getString(R.string.action_retry),
|
||||
getInstallOnReceivedIntent(InstallOnReceived.RETRY_DOWNLOAD, result.url))
|
||||
addAction(R.drawable.ic_clear_grey_24dp_img, context.getString(R.string.action_cancel),
|
||||
getInstallOnReceivedIntent(InstallOnReceived.CANCEL_NOTIFICATION))
|
||||
}
|
||||
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
setProgress(0, 0, false)
|
||||
}
|
||||
val notification = notificationBuilder.build()
|
||||
notification.flags = Notification.FLAG_NO_CLEAR
|
||||
context.notificationManager.notify(InstallOnReceived.notificationId, notification)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns broadcast intent
|
||||
* @param action action name of broadcast intent
|
||||
* @param path path of file | url of file
|
||||
* @return broadcast intent
|
||||
*/
|
||||
fun getInstallOnReceivedIntent(action: String, path: String = ""): PendingIntent {
|
||||
val intent = Intent(context, InstallOnReceived::class.java).apply {
|
||||
this.action = action
|
||||
putExtra(InstallOnReceived.FILE_LOCATION, path)
|
||||
}
|
||||
return PendingIntent.getBroadcast(context, 0, intent, 0)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* BroadcastEvent used to install apk or retry download
|
||||
*/
|
||||
class InstallOnReceived : BroadcastReceiver() {
|
||||
companion object {
|
||||
// Install apk action
|
||||
val INSTALL_APK = "eu.kanade.INSTALL_APK"
|
||||
|
||||
// Retry download action
|
||||
val RETRY_DOWNLOAD = "eu.kanade.RETRY_DOWNLOAD"
|
||||
|
||||
// Retry download action
|
||||
val CANCEL_NOTIFICATION = "eu.kanade.CANCEL_NOTIFICATION"
|
||||
|
||||
// Absolute path of file || URL of file
|
||||
val FILE_LOCATION = "file_location"
|
||||
|
||||
// Id of the notification
|
||||
val notificationId = 2
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
when (intent.action) {
|
||||
// Install apk.
|
||||
INSTALL_APK -> UpdateDownloader.installAPK(context, File(intent.getStringExtra(FILE_LOCATION)))
|
||||
// Retry download.
|
||||
RETRY_DOWNLOAD -> UpdateDownloader(context).execute(intent.getStringExtra(FILE_LOCATION))
|
||||
|
||||
CANCEL_NOTIFICATION -> context.notificationManager.cancel(notificationId)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
package eu.kanade.tachiyomi.data.updater
|
||||
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.SystemClock
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.util.DeviceUtil
|
||||
import eu.kanade.tachiyomi.util.alarmManager
|
||||
import eu.kanade.tachiyomi.util.notification
|
||||
import eu.kanade.tachiyomi.util.notificationManager
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import rx.schedulers.Schedulers
|
||||
|
||||
class UpdateDownloaderAlarm : BroadcastReceiver() {
|
||||
|
||||
companion object {
|
||||
const val CHECK_UPDATE_ACTION = "eu.kanade.CHECK_UPDATE"
|
||||
|
||||
/**
|
||||
* Sets the alarm to run the intent that checks for update
|
||||
* @param context the application context.
|
||||
* @param intervalInHours the time in hours when it will be executed.
|
||||
*/
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun startAlarm(context: Context, intervalInHours: Int = 12, isEnabled: Boolean = PreferencesHelper.getAutomaticUpdateStatus(context)) {
|
||||
// Stop previous running alarms if needed, and do not restart it if the interval is 0.
|
||||
UpdateDownloaderAlarm.stopAlarm(context)
|
||||
if (intervalInHours == 0 || !isEnabled)
|
||||
return
|
||||
|
||||
// Get the time the alarm should fire the event to update.
|
||||
val intervalInMillis = intervalInHours * 60 * 60 * 1000
|
||||
val nextRun = SystemClock.elapsedRealtime() + intervalInMillis
|
||||
|
||||
// Start the alarm.
|
||||
val pendingIntent = getPendingIntent(context)
|
||||
context.alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP,
|
||||
nextRun, intervalInMillis.toLong(), pendingIntent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the alarm if it's running.
|
||||
* @param context the application context.
|
||||
*/
|
||||
fun stopAlarm(context: Context) {
|
||||
val pendingIntent = getPendingIntent(context)
|
||||
context.alarmManager.cancel(pendingIntent)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns broadcast intent
|
||||
* @param context the application context.
|
||||
* @return broadcast intent
|
||||
*/
|
||||
fun getPendingIntent(context: Context): PendingIntent {
|
||||
return PendingIntent.getBroadcast(context, 0,
|
||||
Intent(context, UpdateDownloaderAlarm::class.java).apply {
|
||||
this.action = CHECK_UPDATE_ACTION
|
||||
}, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
when (intent.action) {
|
||||
// Start the alarm when the system is booted.
|
||||
Intent.ACTION_BOOT_COMPLETED -> startAlarm(context)
|
||||
// Update the library when the alarm fires an event.
|
||||
CHECK_UPDATE_ACTION -> checkVersion(context)
|
||||
}
|
||||
}
|
||||
|
||||
fun checkVersion(context: Context) {
|
||||
if (DeviceUtil.isNetworkConnected(context)) {
|
||||
val updateChecker = GithubUpdateChecker(context)
|
||||
updateChecker.checkForApplicationUpdate()
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({ release ->
|
||||
//Get version of latest release
|
||||
var newVersion = release.version
|
||||
newVersion = newVersion.replace("[^\\d.]".toRegex(), "")
|
||||
|
||||
//Check if latest version is different from current version
|
||||
if (newVersion != BuildConfig.VERSION_NAME) {
|
||||
val downloadLink = release.downloadLink
|
||||
|
||||
val n = context.notification() {
|
||||
setContentTitle(context.getString(R.string.update_check_notification_update_available))
|
||||
addAction(android.R.drawable.stat_sys_download_done, context.getString(eu.kanade.tachiyomi.R.string.action_download),
|
||||
UpdateDownloader(context).getInstallOnReceivedIntent(UpdateDownloader.InstallOnReceived.RETRY_DOWNLOAD, downloadLink))
|
||||
setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
}
|
||||
// Displays the progress bar on notification
|
||||
context.notificationManager.notify(0, n);
|
||||
}
|
||||
}, {
|
||||
it.printStackTrace()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -73,5 +73,4 @@ open class BaseActivity : AppCompatActivity() {
|
||||
snack.f()
|
||||
snack.show()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
package eu.kanade.tachiyomi.ui.setting
|
||||
|
||||
import android.os.Bundle
|
||||
import android.support.v7.preference.SwitchPreferenceCompat
|
||||
import android.view.View
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.updater.GithubUpdateChecker
|
||||
import eu.kanade.tachiyomi.data.updater.UpdateDownloader
|
||||
import eu.kanade.tachiyomi.data.updater.UpdateDownloaderAlarm
|
||||
import eu.kanade.tachiyomi.util.toast
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
@ -27,6 +29,10 @@ class SettingsAboutFragment : SettingsNestedFragment() {
|
||||
*/
|
||||
private var releaseSubscription: Subscription? = null
|
||||
|
||||
val automaticUpdateToggle by lazy {
|
||||
findPreference(getString(R.string.pref_enable_automatic_updates_key)) as SwitchPreferenceCompat
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance(resourcePreference: Int, resourceTitle: Int): SettingsNestedFragment {
|
||||
@ -45,11 +51,25 @@ class SettingsAboutFragment : SettingsNestedFragment() {
|
||||
else
|
||||
BuildConfig.VERSION_NAME
|
||||
|
||||
//Set onClickListener to check for new version
|
||||
version.setOnPreferenceClickListener {
|
||||
if (!BuildConfig.DEBUG && BuildConfig.INCLUDE_UPDATER)
|
||||
checkVersion()
|
||||
true
|
||||
if (!BuildConfig.DEBUG && BuildConfig.INCLUDE_UPDATER) {
|
||||
//Set onClickListener to check for new version
|
||||
version.setOnPreferenceClickListener {
|
||||
true
|
||||
}
|
||||
|
||||
automaticUpdateToggle.isEnabled = true
|
||||
automaticUpdateToggle.setOnPreferenceChangeListener { preference, any ->
|
||||
val status = any as Boolean
|
||||
UpdateDownloaderAlarm.startAlarm(activity, 12, status)
|
||||
true
|
||||
}
|
||||
|
||||
automaticUpdateToggle.isEnabled = true
|
||||
automaticUpdateToggle.setOnPreferenceChangeListener { preference, any ->
|
||||
val status = any as Boolean
|
||||
UpdateDownloaderAlarm.startAlarm(activity, 12, status)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
buildTime.summary = getFormattedBuildTime()
|
||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.setting
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.support.v14.preference.MultiSelectListPreference
|
||||
import android.support.v4.app.TaskStackBuilder
|
||||
import android.support.v7.preference.Preference
|
||||
import android.view.View
|
||||
@ -33,13 +34,28 @@ class SettingsGeneralFragment : SettingsNestedFragment() {
|
||||
findPreference(getString(R.string.pref_library_update_interval_key)) as IntListPreference
|
||||
}
|
||||
|
||||
val updateRestriction by lazy {
|
||||
findPreference(getString(R.string.pref_library_update_restriction_key)) as MultiSelectListPreference
|
||||
}
|
||||
|
||||
val themePreference by lazy {
|
||||
findPreference(getString(R.string.pref_theme_key)) as IntListPreference
|
||||
}
|
||||
|
||||
var updateIntervalSubscription: Subscription? = null
|
||||
|
||||
var columnsSubscription: Subscription? = null
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
updateIntervalSubscription = preferences.libraryUpdateInterval().asObservable()
|
||||
.subscribe { updateRestriction.isVisible = it > 0 }
|
||||
|
||||
columnsSubscription = Observable.combineLatest(
|
||||
preferences.portraitColumns().asObservable(),
|
||||
preferences.landscapeColumns().asObservable())
|
||||
{ portraitColumns, landscapeColumns -> Pair(portraitColumns, landscapeColumns) }
|
||||
.subscribe { updateColumnsSummary(it.first, it.second) }
|
||||
|
||||
updateInterval.setOnPreferenceChangeListener { preference, newValue ->
|
||||
LibraryUpdateAlarm.startAlarm(activity, (newValue as String).toInt())
|
||||
true
|
||||
@ -57,17 +73,11 @@ class SettingsGeneralFragment : SettingsNestedFragment() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
columnsSubscription = Observable.combineLatest(preferences.portraitColumns().asObservable(),
|
||||
preferences.landscapeColumns().asObservable(),
|
||||
{ portraitColumns, landscapeColumns -> Pair(portraitColumns, landscapeColumns) })
|
||||
.subscribe { updateColumnsSummary(it.first, it.second) }
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
override fun onDestroyView() {
|
||||
updateIntervalSubscription?.unsubscribe()
|
||||
columnsSubscription?.unsubscribe()
|
||||
super.onPause()
|
||||
super.onDestroyView()
|
||||
|
||||
}
|
||||
|
||||
override fun onDisplayPreferenceDialog(preference: Preference) {
|
||||
|
@ -11,7 +11,7 @@ object DeviceUtil {
|
||||
val intent = context.registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
|
||||
intent?.let {
|
||||
val plugged = it.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)
|
||||
return plugged == BatteryManager.BATTERY_PLUGGED_AC || plugged == BatteryManager.BATTERY_PLUGGED_USB
|
||||
return plugged == BatteryManager.BATTERY_PLUGGED_AC || plugged == BatteryManager.BATTERY_PLUGGED_USB || plugged == BatteryManager.BATTERY_PLUGGED_WIRELESS
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 717 B |
Binary file not shown.
After Width: | Height: | Size: 487 B |
Binary file not shown.
After Width: | Height: | Size: 871 B |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
@ -126,4 +126,14 @@
|
||||
<item>48</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="library_update_restrictions">
|
||||
<item>@string/wifi</item>
|
||||
<item>@string/charging</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="library_update_restrictions_values">
|
||||
<item>wifi</item>
|
||||
<item>ac</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
@ -13,10 +13,10 @@
|
||||
<string name="pref_library_columns_landscape_key">pref_library_columns_landscape_key</string>
|
||||
<string name="pref_library_update_interval_key">pref_library_update_interval_key</string>
|
||||
<string name="pref_update_only_non_completed_key">pref_update_only_non_completed_key</string>
|
||||
<string name="pref_update_only_when_charging_key">pref_update_only_when_charging_key</string>
|
||||
<string name="pref_auto_update_manga_sync_key">pref_auto_update_manga_sync_key</string>
|
||||
<string name="pref_ask_update_manga_sync_key">pref_ask_update_manga_sync_key</string>
|
||||
<string name="pref_theme_key">pref_theme_key</string>
|
||||
<string name="pref_library_update_restriction_key">library_update_restriction</string>
|
||||
|
||||
<string name="pref_default_viewer_key">pref_default_viewer_key</string>
|
||||
<string name="pref_image_scale_type_key">pref_image_scale_type_key</string>
|
||||
@ -52,8 +52,10 @@
|
||||
<string name="pref_clear_chapter_cache_key">pref_clear_chapter_cache_key</string>
|
||||
<string name="pref_clear_database_key">pref_clear_database_key</string>
|
||||
|
||||
|
||||
<string name="pref_version">pref_version</string>
|
||||
<string name="pref_build_time">pref_build_time</string>
|
||||
<string name="pref_enable_automatic_updates_key">pref_enable_automatic_updates_key</string>
|
||||
|
||||
<string name="pref_display_catalogue_as_list">pref_display_catalogue_as_list</string>
|
||||
<string name="pref_last_catalogue_source_key">pref_last_catalogue_source_key</string>
|
||||
|
@ -51,6 +51,7 @@
|
||||
<string name="action_cancel">Cancel</string>
|
||||
<string name="action_sort">Sort</string>
|
||||
<string name="action_force">Force refresh</string>
|
||||
<string name="action_install">Install</string>
|
||||
|
||||
<!-- Operations -->
|
||||
<string name="deleting">Deleting…</string>
|
||||
@ -72,8 +73,6 @@
|
||||
<string name="landscape">Landscape</string>
|
||||
<string name="default_columns">Default</string>
|
||||
<string name="pref_library_update_interval">Library update frequency</string>
|
||||
<string name="pref_update_only_non_completed">Only update incomplete manga</string>
|
||||
<string name="pref_update_only_when_charging">Only update when charging</string>
|
||||
<string name="update_never">Manual</string>
|
||||
<string name="update_1hour">Hourly</string>
|
||||
<string name="update_2hour">Every 2 hours</string>
|
||||
@ -82,13 +81,17 @@
|
||||
<string name="update_12hour">Every 12 hours</string>
|
||||
<string name="update_24hour">Daily</string>
|
||||
<string name="update_48hour">Every 2 days</string>
|
||||
<string name="pref_library_update_restriction">Library update restrictions</string>
|
||||
<string name="pref_library_update_restriction_summary">Update only when the conditions are met</string>
|
||||
<string name="wifi">Wi-Fi</string>
|
||||
<string name="charging">Charging</string>
|
||||
<string name="pref_update_only_non_completed">Only update incomplete manga</string>
|
||||
<string name="pref_auto_update_manga_sync">Sync chapters after reading</string>
|
||||
<string name="pref_ask_update_manga_sync">Confirm before updating</string>
|
||||
<string name="pref_theme">Application theme</string>
|
||||
<string name="light_theme">Main theme</string>
|
||||
<string name="dark_theme">Dark theme</string>
|
||||
|
||||
|
||||
<!-- Reader section -->
|
||||
<string name="pref_hide_status_bar">Hide status bar</string>
|
||||
<string name="pref_lock_orientation">Lock orientation</string>
|
||||
@ -166,7 +169,8 @@
|
||||
<!-- About section -->
|
||||
<string name="version">Version</string>
|
||||
<string name="build_time">Build time</string>
|
||||
|
||||
<string name="pref_enable_automatic_updates">Check for updates</string>
|
||||
<string name="pref_enable_automatic_updates_summary">Automatically check for application updates</string>
|
||||
<!-- ACRA -->
|
||||
<string name="pref_enable_acra">Send crash reports</string>
|
||||
<string name="pref_acra_summary">Helps fix any bugs. No sensitive data will be sent</string>
|
||||
@ -282,6 +286,13 @@
|
||||
<string name="update_check_download_started">Download started</string>
|
||||
<string name="update_check_look_for_updates">Looking for updates</string>
|
||||
|
||||
<!--UpdateCheck Notifications-->
|
||||
<string name="update_check_notification_file_download">Download update</string>
|
||||
<string name="update_check_notification_download_in_progress">Download in progress</string>
|
||||
<string name="update_check_notification_download_complete">Download complete</string>
|
||||
<string name="update_check_notification_download_error">Download error</string>
|
||||
<string name="update_check_notification_update_available">Update available</string>
|
||||
|
||||
<!--Content Description-->
|
||||
<string name="description_backdrop">Backdrop image of selected manga</string>
|
||||
<string name="description_cover">Cover of selected manga</string>
|
||||
|
@ -3,19 +3,26 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="true"
|
||||
android:key="acra.enable"
|
||||
android:title="@string/pref_enable_acra"
|
||||
android:summary="@string/pref_acra_summary"
|
||||
android:defaultValue="true"/>
|
||||
android:title="@string/pref_enable_acra"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:enabled="false"
|
||||
android:key="@string/pref_enable_automatic_updates_key"
|
||||
android:summary="@string/pref_enable_automatic_updates_summary"
|
||||
android:title="@string/pref_enable_automatic_updates"/>
|
||||
|
||||
<Preference
|
||||
android:key="@string/pref_version"
|
||||
android:title="@string/version"
|
||||
android:persistent="false" />
|
||||
android:persistent="false"
|
||||
android:title="@string/version"/>
|
||||
|
||||
<Preference
|
||||
android:key="@string/pref_build_time"
|
||||
android:title="@string/build_time"
|
||||
android:persistent="false" />
|
||||
android:persistent="false"
|
||||
android:title="@string/build_time"/>
|
||||
|
||||
</android.support.v7.preference.PreferenceScreen>
|
@ -3,13 +3,13 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<Preference
|
||||
android:title="@string/pref_clear_chapter_cache"
|
||||
android:key="@string/pref_clear_chapter_cache_key" />
|
||||
android:key="@string/pref_clear_chapter_cache_key"
|
||||
android:title="@string/pref_clear_chapter_cache"/>
|
||||
|
||||
<Preference
|
||||
android:title="@string/pref_clear_database"
|
||||
android:key="@string/pref_clear_database_key"
|
||||
android:summary="@string/pref_clear_database_summary"/>
|
||||
android:summary="@string/pref_clear_database_summary"
|
||||
android:title="@string/pref_clear_database"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
|
@ -24,14 +24,16 @@
|
||||
android:summary="%s"
|
||||
android:title="@string/pref_library_update_interval"/>
|
||||
|
||||
<MultiSelectListPreference
|
||||
android:entries="@array/library_update_restrictions"
|
||||
android:entryValues="@array/library_update_restrictions_values"
|
||||
android:key="@string/pref_library_update_restriction_key"
|
||||
android:summary="@string/pref_library_update_restriction_summary"
|
||||
android:title="@string/pref_library_update_restriction" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="@string/pref_update_only_non_completed_key"
|
||||
android:title="@string/pref_update_only_non_completed"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:defaultValue="false"
|
||||
android:key="@string/pref_update_only_when_charging_key"
|
||||
android:title="@string/pref_update_only_when_charging"/>
|
||||
|
||||
</android.support.v7.preference.PreferenceScreen>
|
@ -101,7 +101,7 @@ public class LibraryUpdateAlarmTest {
|
||||
@Test
|
||||
public void testLibraryUpdateServiceIsStartedWhenUpdateIntentIsReceived() {
|
||||
Intent intent = new Intent(context, LibraryUpdateService.class);
|
||||
intent.putExtra("is_forced", false);
|
||||
intent.putExtra("is_manual", false);
|
||||
assertThat(app.getNextStartedService()).isNotEqualTo(intent);
|
||||
|
||||
LibraryUpdateAlarm alarm = new LibraryUpdateAlarm();
|
||||
|
Loading…
Reference in New Issue
Block a user