Convert NewVersionWorker to Kotlin
This commit is contained in:
parent
71f141f3f8
commit
b8b97fa6d4
|
@ -1,175 +0,0 @@
|
||||||
package org.schabi.newpipe;
|
|
||||||
|
|
||||||
import android.app.PendingIntent;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.SharedPreferences;
|
|
||||||
import android.net.Uri;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.core.app.NotificationCompat;
|
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
|
||||||
import androidx.preference.PreferenceManager;
|
|
||||||
import androidx.work.OneTimeWorkRequest;
|
|
||||||
import androidx.work.WorkManager;
|
|
||||||
import androidx.work.WorkRequest;
|
|
||||||
import androidx.work.Worker;
|
|
||||||
import androidx.work.WorkerParameters;
|
|
||||||
|
|
||||||
import com.grack.nanojson.JsonObject;
|
|
||||||
import com.grack.nanojson.JsonParser;
|
|
||||||
import com.grack.nanojson.JsonParserException;
|
|
||||||
|
|
||||||
import org.schabi.newpipe.extractor.downloader.Response;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
|
|
||||||
import org.schabi.newpipe.util.ReleaseVersionUtil;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public final class NewVersionWorker extends Worker {
|
|
||||||
|
|
||||||
private static final boolean DEBUG = MainActivity.DEBUG;
|
|
||||||
private static final String TAG = NewVersionWorker.class.getSimpleName();
|
|
||||||
private static final String NEWPIPE_API_URL = "https://newpipe.net/api/data.json";
|
|
||||||
|
|
||||||
public NewVersionWorker(@NonNull final Context context,
|
|
||||||
@NonNull final WorkerParameters workerParams) {
|
|
||||||
super(context, workerParams);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method to compare the current and latest available app version.
|
|
||||||
* If a newer version is available, we show the update notification.
|
|
||||||
*
|
|
||||||
* @param versionName Name of new version
|
|
||||||
* @param apkLocationUrl Url with the new apk
|
|
||||||
* @param versionCode Code of new version
|
|
||||||
*/
|
|
||||||
private static void compareAppVersionAndShowNotification(final String versionName,
|
|
||||||
final String apkLocationUrl,
|
|
||||||
final int versionCode) {
|
|
||||||
if (BuildConfig.VERSION_CODE >= versionCode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final App app = App.getApp();
|
|
||||||
// A pending intent to open the apk location url in the browser.
|
|
||||||
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(apkLocationUrl));
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
final PendingIntent pendingIntent = PendingIntent.getActivity(app, 0, intent, 0);
|
|
||||||
|
|
||||||
final String channelId = app.getString(R.string.app_update_notification_channel_id);
|
|
||||||
final NotificationCompat.Builder notificationBuilder
|
|
||||||
= new NotificationCompat.Builder(app, channelId)
|
|
||||||
.setSmallIcon(R.drawable.ic_newpipe_update)
|
|
||||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.setContentTitle(app.getString(R.string.app_update_notification_content_title))
|
|
||||||
.setContentText(app.getString(R.string.app_update_notification_content_text)
|
|
||||||
+ " " + versionName);
|
|
||||||
|
|
||||||
final NotificationManagerCompat notificationManager
|
|
||||||
= NotificationManagerCompat.from(app);
|
|
||||||
notificationManager.notify(2000, notificationBuilder.build());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkNewVersion() throws IOException, ReCaptchaException {
|
|
||||||
final App app = App.getApp();
|
|
||||||
|
|
||||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(app);
|
|
||||||
|
|
||||||
// Check if the current apk is a github one or not.
|
|
||||||
if (!ReleaseVersionUtil.isReleaseApk()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the last request has happened a certain time ago
|
|
||||||
// to reduce the number of API requests.
|
|
||||||
final long expiry = prefs.getLong(app.getString(R.string.update_expiry_key), 0);
|
|
||||||
if (!ReleaseVersionUtil.isLastUpdateCheckExpired(expiry)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a network request to get latest NewPipe data.
|
|
||||||
final Response response = DownloaderImpl.getInstance().get(NEWPIPE_API_URL);
|
|
||||||
handleResponse(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleResponse(@NonNull final Response response) {
|
|
||||||
final App app = App.getApp();
|
|
||||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(app);
|
|
||||||
try {
|
|
||||||
// Store a timestamp which needs to be exceeded,
|
|
||||||
// before a new request to the API is made.
|
|
||||||
final long newExpiry = ReleaseVersionUtil
|
|
||||||
.coerceUpdateCheckExpiry(response.getHeader("expires"));
|
|
||||||
prefs.edit()
|
|
||||||
.putLong(app.getString(R.string.update_expiry_key), newExpiry)
|
|
||||||
.apply();
|
|
||||||
} catch (final Exception e) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.w(TAG, "Could not extract and save new expiry date", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the json from the response.
|
|
||||||
try {
|
|
||||||
|
|
||||||
final JsonObject githubStableObject = JsonParser.object()
|
|
||||||
.from(response.responseBody()).getObject("flavors")
|
|
||||||
.getObject("github").getObject("stable");
|
|
||||||
|
|
||||||
final String versionName = githubStableObject.getString("version");
|
|
||||||
final int versionCode = githubStableObject.getInt("version_code");
|
|
||||||
final String apkLocationUrl = githubStableObject.getString("apk");
|
|
||||||
|
|
||||||
compareAppVersionAndShowNotification(versionName,
|
|
||||||
apkLocationUrl, versionCode);
|
|
||||||
} catch (final JsonParserException e) {
|
|
||||||
// Most likely something is wrong in data received from NEWPIPE_API_URL.
|
|
||||||
// Do not alarm user and fail silently.
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.w(TAG, "Could not get NewPipe API: invalid json", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a new worker which
|
|
||||||
* checks if all conditions for performing a version check are met,
|
|
||||||
* fetches the API endpoint {@link #NEWPIPE_API_URL} containing info
|
|
||||||
* about the latest NewPipe version
|
|
||||||
* and displays a notification about ana available update.
|
|
||||||
* <br>
|
|
||||||
* Following conditions need to be met, before data is request from the server:
|
|
||||||
* <ul>
|
|
||||||
* <li> The app is signed with the correct signing key (by TeamNewPipe / schabi).
|
|
||||||
* If the signing key differs from the one used upstream, the update cannot be installed.</li>
|
|
||||||
* <li>The user enabled searching for and notifying about updates in the settings.</li>
|
|
||||||
* <li>The app did not recently check for updates.
|
|
||||||
* We do not want to make unnecessary connections and DOS our servers.</li>
|
|
||||||
* </ul>
|
|
||||||
*/
|
|
||||||
public static void enqueueNewVersionCheckingWork(final Context context) {
|
|
||||||
final WorkRequest workRequest =
|
|
||||||
new OneTimeWorkRequest.Builder(NewVersionWorker.class).build();
|
|
||||||
WorkManager.getInstance(context).enqueue(workRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Result doWork() {
|
|
||||||
try {
|
|
||||||
checkNewVersion();
|
|
||||||
} catch (final IOException e) {
|
|
||||||
Log.w(TAG, "Could not fetch NewPipe API: probably network problem", e);
|
|
||||||
return Result.failure();
|
|
||||||
} catch (final ReCaptchaException e) {
|
|
||||||
Log.e(TAG, "ReCaptchaException should never happen here.", e);
|
|
||||||
return Result.failure();
|
|
||||||
}
|
|
||||||
return Result.success();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
package org.schabi.newpipe
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
|
import androidx.core.app.NotificationManagerCompat
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import androidx.work.OneTimeWorkRequest
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.WorkRequest
|
||||||
|
import androidx.work.Worker
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import com.grack.nanojson.JsonParser
|
||||||
|
import com.grack.nanojson.JsonParserException
|
||||||
|
import org.schabi.newpipe.extractor.downloader.Response
|
||||||
|
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException
|
||||||
|
import org.schabi.newpipe.util.ReleaseVersionUtil.coerceUpdateCheckExpiry
|
||||||
|
import org.schabi.newpipe.util.ReleaseVersionUtil.isLastUpdateCheckExpired
|
||||||
|
import org.schabi.newpipe.util.ReleaseVersionUtil.isReleaseApk
|
||||||
|
import java.io.IOException
|
||||||
|
|
||||||
|
class NewVersionWorker(
|
||||||
|
context: Context,
|
||||||
|
workerParams: WorkerParameters
|
||||||
|
) : Worker(context, workerParams) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to compare the current and latest available app version.
|
||||||
|
* If a newer version is available, we show the update notification.
|
||||||
|
*
|
||||||
|
* @param versionName Name of new version
|
||||||
|
* @param apkLocationUrl Url with the new apk
|
||||||
|
* @param versionCode Code of new version
|
||||||
|
*/
|
||||||
|
private fun compareAppVersionAndShowNotification(
|
||||||
|
versionName: String,
|
||||||
|
apkLocationUrl: String?,
|
||||||
|
versionCode: Int
|
||||||
|
) {
|
||||||
|
if (BuildConfig.VERSION_CODE >= versionCode) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val app = App.getApp()
|
||||||
|
|
||||||
|
// A pending intent to open the apk location url in the browser.
|
||||||
|
val intent = Intent(Intent.ACTION_VIEW, apkLocationUrl?.toUri())
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
|
val pendingIntent = PendingIntent.getActivity(app, 0, intent, 0)
|
||||||
|
val channelId = app.getString(R.string.app_update_notification_channel_id)
|
||||||
|
val notificationBuilder = NotificationCompat.Builder(app, channelId)
|
||||||
|
.setSmallIcon(R.drawable.ic_newpipe_update)
|
||||||
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setContentTitle(app.getString(R.string.app_update_notification_content_title))
|
||||||
|
.setContentText(
|
||||||
|
app.getString(R.string.app_update_notification_content_text) +
|
||||||
|
" " + versionName
|
||||||
|
)
|
||||||
|
val notificationManager = NotificationManagerCompat.from(app)
|
||||||
|
notificationManager.notify(2000, notificationBuilder.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(IOException::class, ReCaptchaException::class)
|
||||||
|
private fun checkNewVersion() {
|
||||||
|
// Check if the current apk is a github one or not.
|
||||||
|
if (!isReleaseApk()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||||
|
// Check if the last request has happened a certain time ago
|
||||||
|
// to reduce the number of API requests.
|
||||||
|
val expiry = prefs.getLong(applicationContext.getString(R.string.update_expiry_key), 0)
|
||||||
|
if (!isLastUpdateCheckExpired(expiry)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a network request to get latest NewPipe data.
|
||||||
|
val response = DownloaderImpl.getInstance().get(NEWPIPE_API_URL)
|
||||||
|
handleResponse(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleResponse(response: Response) {
|
||||||
|
val prefs = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||||
|
try {
|
||||||
|
// Store a timestamp which needs to be exceeded,
|
||||||
|
// before a new request to the API is made.
|
||||||
|
val newExpiry = coerceUpdateCheckExpiry(response.getHeader("expires"))
|
||||||
|
prefs.edit {
|
||||||
|
putLong(applicationContext.getString(R.string.update_expiry_key), newExpiry)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.w(TAG, "Could not extract and save new expiry date", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the json from the response.
|
||||||
|
try {
|
||||||
|
val githubStableObject = JsonParser.`object`()
|
||||||
|
.from(response.responseBody()).getObject("flavors")
|
||||||
|
.getObject("github").getObject("stable")
|
||||||
|
|
||||||
|
val versionName = githubStableObject.getString("version")
|
||||||
|
val versionCode = githubStableObject.getInt("version_code")
|
||||||
|
val apkLocationUrl = githubStableObject.getString("apk")
|
||||||
|
compareAppVersionAndShowNotification(versionName, apkLocationUrl, versionCode)
|
||||||
|
} catch (e: JsonParserException) {
|
||||||
|
// Most likely something is wrong in data received from NEWPIPE_API_URL.
|
||||||
|
// Do not alarm user and fail silently.
|
||||||
|
if (DEBUG) {
|
||||||
|
Log.w(TAG, "Could not get NewPipe API: invalid json", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doWork(): Result {
|
||||||
|
try {
|
||||||
|
checkNewVersion()
|
||||||
|
} catch (e: IOException) {
|
||||||
|
Log.w(TAG, "Could not fetch NewPipe API: probably network problem", e)
|
||||||
|
return Result.failure()
|
||||||
|
} catch (e: ReCaptchaException) {
|
||||||
|
Log.e(TAG, "ReCaptchaException should never happen here.", e)
|
||||||
|
return Result.failure()
|
||||||
|
}
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val DEBUG = MainActivity.DEBUG
|
||||||
|
private val TAG = NewVersionWorker::class.java.simpleName
|
||||||
|
private const val NEWPIPE_API_URL = "https://newpipe.net/api/data.json"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a new worker which
|
||||||
|
* checks if all conditions for performing a version check are met,
|
||||||
|
* fetches the API endpoint [.NEWPIPE_API_URL] containing info
|
||||||
|
* about the latest NewPipe version
|
||||||
|
* and displays a notification about ana available update.
|
||||||
|
* <br></br>
|
||||||
|
* Following conditions need to be met, before data is request from the server:
|
||||||
|
*
|
||||||
|
* * The app is signed with the correct signing key (by TeamNewPipe / schabi).
|
||||||
|
* If the signing key differs from the one used upstream, the update cannot be installed.
|
||||||
|
* * The user enabled searching for and notifying about updates in the settings.
|
||||||
|
* * The app did not recently check for updates.
|
||||||
|
* We do not want to make unnecessary connections and DOS our servers.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@JvmStatic
|
||||||
|
fun enqueueNewVersionCheckingWork(context: Context) {
|
||||||
|
val workRequest: WorkRequest =
|
||||||
|
OneTimeWorkRequest.Builder(NewVersionWorker::class.java).build()
|
||||||
|
WorkManager.getInstance(context).enqueue(workRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -94,7 +94,6 @@ object ReleaseVersionUtil {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
fun isLastUpdateCheckExpired(expiry: Long): Boolean {
|
fun isLastUpdateCheckExpired(expiry: Long): Boolean {
|
||||||
return Instant.ofEpochSecond(expiry).isBefore(Instant.now())
|
return Instant.ofEpochSecond(expiry).isBefore(Instant.now())
|
||||||
}
|
}
|
||||||
|
@ -104,7 +103,6 @@ object ReleaseVersionUtil {
|
||||||
*
|
*
|
||||||
* @return Epoch second of expiry date time
|
* @return Epoch second of expiry date time
|
||||||
*/
|
*/
|
||||||
@JvmStatic
|
|
||||||
fun coerceUpdateCheckExpiry(expiryString: String?): Long {
|
fun coerceUpdateCheckExpiry(expiryString: String?): Long {
|
||||||
val now = ZonedDateTime.now()
|
val now = ZonedDateTime.now()
|
||||||
return expiryString?.let {
|
return expiryString?.let {
|
||||||
|
|
Loading…
Reference in New Issue