Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,9 @@
<service
android:name=".RouterActivity$FetcherService"
android:exported="false" />
<service
android:name=".CheckForNewAppVersion"
android:exported="false" />

<!-- opting out of sending metrics to Google in Android System WebView -->
<meta-data android:name="android.webkit.WebView.MetricsOptOut" android:value="true" />
Expand Down
12 changes: 3 additions & 9 deletions app/src/main/java/org/schabi/newpipe/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationChannelCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.multidex.MultiDexApplication;
Expand Down Expand Up @@ -35,14 +34,15 @@
import java.util.Collections;
import java.util.List;

import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.exceptions.CompositeException;
import io.reactivex.rxjava3.exceptions.MissingBackpressureException;
import io.reactivex.rxjava3.exceptions.OnErrorNotImplementedException;
import io.reactivex.rxjava3.exceptions.UndeliverableException;
import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.plugins.RxJavaPlugins;

import static org.schabi.newpipe.CheckForNewAppVersion.startNewVersionCheckService;

/*
* Copyright (C) Hans-Christoph Steiner 2016 <hans@eds.org>
* App.java is part of NewPipe.
Expand All @@ -66,9 +66,6 @@ public class App extends MultiDexApplication {
private static final String TAG = App.class.toString();
private static App app;

@Nullable
private Disposable disposable = null;

@NonNull
public static App getApp() {
return app;
Expand Down Expand Up @@ -110,14 +107,11 @@ public void onCreate() {
configureRxJavaErrorHandler();

// Check for new version
disposable = CheckForNewAppVersion.checkNewVersion(this);
startNewVersionCheckService();
}

@Override
public void onTerminate() {
if (disposable != null) {
disposable.dispose();
}
super.onTerminate();
PicassoHelper.terminate();
}
Expand Down
142 changes: 76 additions & 66 deletions app/src/main/java/org/schabi/newpipe/CheckForNewAppVersion.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.schabi.newpipe;

import android.app.Application;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.SharedPreferences;
Expand All @@ -25,8 +26,11 @@
import org.schabi.newpipe.error.ErrorActivity;
import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.UserAction;
import org.schabi.newpipe.extractor.downloader.Response;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
Expand All @@ -35,13 +39,10 @@
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;

public final class CheckForNewAppVersion {
private CheckForNewAppVersion() { }
public final class CheckForNewAppVersion extends IntentService {
public CheckForNewAppVersion() {
super("CheckForNewAppVersion");
}

private static final boolean DEBUG = MainActivity.DEBUG;
private static final String TAG = CheckForNewAppVersion.class.getSimpleName();
Expand Down Expand Up @@ -165,78 +166,87 @@ public static boolean isGithubApk(@NonNull final App app) {
return getCertificateSHA1Fingerprint(app).equals(GITHUB_APK_SHA1);
}

@Nullable
public static Disposable checkNewVersion(@NonNull final App app) {
private void checkNewVersion() throws IOException, ReCaptchaException {
final App app = App.getApp();

final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(app);
final NewVersionManager manager = new NewVersionManager();

// Check if user has enabled/disabled update checking
// and if the current apk is a github one or not.
if (!prefs.getBoolean(app.getString(R.string.update_app_key), true) || !isGithubApk(app)) {
return null;
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 (!manager.isExpired(expiry)) {
return null;
return;
}

// Make a network request to get latest NewPipe data.
final Response response = DownloaderImpl.getInstance().get(NEWPIPE_API_URL);
handleResponse(response, manager, prefs, app);
}

private void handleResponse(@NonNull final Response response,
@NonNull final NewVersionManager manager,
@NonNull final SharedPreferences prefs,
@NonNull final App app) {
try {
// Store a timestamp which needs to be exceeded,
// before a new request to the API is made.
final long newExpiry = manager
.coerceExpiry(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(app, 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);
}
}
}

public static void startNewVersionCheckService() {
final Intent intent = new Intent(App.getApp().getApplicationContext(),
CheckForNewAppVersion.class);
App.getApp().startService(intent);
}

@Override
protected void onHandleIntent(@Nullable final Intent intent) {
try {
checkNewVersion();
} catch (final IOException e) {
Log.w(TAG, "Could not fetch NewPipe API: probably network problem", e);
} catch (final ReCaptchaException e) {
Log.e(TAG, "ReCaptchaException should never happen here.", e);
}

return Maybe
.fromCallable(() -> {
if (!isConnected(app)) {
return null;
}

// Make a network request to get latest NewPipe data.
return DownloaderImpl.getInstance().get(NEWPIPE_API_URL);
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
response -> {
try {
// Store a timestamp which needs to be exceeded,
// before a new request to the API is made.
final long newExpiry = manager
.coerceExpiry(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(app, versionName,
apkLocationUrl, versionCode);
} catch (final JsonParserException e) {
// connectivity problems, do not alarm user and fail silently
if (DEBUG) {
Log.w(TAG, "Could not get NewPipe API: invalid json", e);
}
}
},
e -> {
// connectivity problems, do not alarm user and fail silently
if (DEBUG) {
Log.w(TAG, "Could not get NewPipe API: network problem", e);
}
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,21 @@

import org.schabi.newpipe.R;

import static org.schabi.newpipe.CheckForNewAppVersion.startNewVersionCheckService;

public class UpdateSettingsFragment extends BasePreferenceFragment {
private final Preference.OnPreferenceChangeListener updatePreferenceChange
= (preference, newValue) -> {
= (preference, checkForUpdates) -> {
defaultPreferences.edit()
.putBoolean(getString(R.string.update_app_key), (boolean) newValue).apply();
.putBoolean(getString(R.string.update_app_key), (boolean) checkForUpdates).apply();

if ((boolean) checkForUpdates) {
// Search for updates immediately when update checks are enabled.
// Reset the expire time. This is necessary to check for an update immediately.
defaultPreferences.edit()
.putLong(getString(R.string.update_expiry_key), 0).apply();
startNewVersionCheckService();
}
return true;
};

Expand Down