Merge pull request #4499 from Isira-Seneviratne/Replace_AsyncTasks_with_ReactiveX
Use RxJava instead of AsyncTask.
This commit is contained in:
commit
c193b4f07c
|
@ -36,6 +36,7 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.exceptions.CompositeException;
|
import io.reactivex.exceptions.CompositeException;
|
||||||
import io.reactivex.exceptions.MissingBackpressureException;
|
import io.reactivex.exceptions.MissingBackpressureException;
|
||||||
import io.reactivex.exceptions.OnErrorNotImplementedException;
|
import io.reactivex.exceptions.OnErrorNotImplementedException;
|
||||||
|
@ -65,6 +66,9 @@ public class App extends MultiDexApplication {
|
||||||
protected static final String TAG = App.class.toString();
|
protected static final String TAG = App.class.toString();
|
||||||
private static App app;
|
private static App app;
|
||||||
|
|
||||||
|
private Disposable disposable = null;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
public static App getApp() {
|
public static App getApp() {
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
@ -100,7 +104,15 @@ public class App extends MultiDexApplication {
|
||||||
configureRxJavaErrorHandler();
|
configureRxJavaErrorHandler();
|
||||||
|
|
||||||
// Check for new version
|
// Check for new version
|
||||||
new CheckForNewAppVersionTask().execute();
|
disposable = CheckForNewAppVersion.checkNewVersion(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTerminate() {
|
||||||
|
if (disposable != null) {
|
||||||
|
disposable.dispose();
|
||||||
|
}
|
||||||
|
super.onTerminate();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Downloader getDownloader() {
|
protected Downloader getDownloader() {
|
||||||
|
|
|
@ -9,9 +9,9 @@ import android.content.pm.PackageManager;
|
||||||
import android.content.pm.Signature;
|
import android.content.pm.Signature;
|
||||||
import android.net.ConnectivityManager;
|
import android.net.ConnectivityManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
import androidx.core.app.NotificationManagerCompat;
|
import androidx.core.app.NotificationManagerCompat;
|
||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
|
@ -35,16 +35,18 @@ import java.security.cert.CertificateException;
|
||||||
import java.security.cert.CertificateFactory;
|
import java.security.cert.CertificateFactory;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
|
|
||||||
/**
|
import io.reactivex.Observable;
|
||||||
* AsyncTask to check if there is a newer version of the NewPipe github apk available or not.
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
* If there is a newer version we show a notification, informing the user. On tapping
|
import io.reactivex.disposables.Disposable;
|
||||||
* the notification, the user will be directed to the download link.
|
import io.reactivex.disposables.Disposables;
|
||||||
*/
|
import io.reactivex.schedulers.Schedulers;
|
||||||
public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|
||||||
private static final boolean DEBUG = MainActivity.DEBUG;
|
public final class CheckForNewAppVersion {
|
||||||
private static final String TAG = CheckForNewAppVersionTask.class.getSimpleName();
|
private CheckForNewAppVersion() { }
|
||||||
|
|
||||||
|
private static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
private static final String TAG = CheckForNewAppVersion.class.getSimpleName();
|
||||||
|
|
||||||
private static final Application APP = App.getApp();
|
|
||||||
private static final String GITHUB_APK_SHA1
|
private static final String GITHUB_APK_SHA1
|
||||||
= "B0:2E:90:7C:1C:D6:FC:57:C3:35:F0:88:D0:8F:50:5F:94:E4:D2:15";
|
= "B0:2E:90:7C:1C:D6:FC:57:C3:35:F0:88:D0:8F:50:5F:94:E4:D2:15";
|
||||||
private static final String NEWPIPE_API_URL = "https://newpipe.schabi.org/api/data.json";
|
private static final String NEWPIPE_API_URL = "https://newpipe.schabi.org/api/data.json";
|
||||||
|
@ -52,18 +54,19 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
||||||
/**
|
/**
|
||||||
* Method to get the apk's SHA1 key. See https://stackoverflow.com/questions/9293019/#22506133.
|
* Method to get the apk's SHA1 key. See https://stackoverflow.com/questions/9293019/#22506133.
|
||||||
*
|
*
|
||||||
|
* @param application The application
|
||||||
* @return String with the apk's SHA1 fingeprint in hexadecimal
|
* @return String with the apk's SHA1 fingeprint in hexadecimal
|
||||||
*/
|
*/
|
||||||
private static String getCertificateSHA1Fingerprint() {
|
private static String getCertificateSHA1Fingerprint(@NonNull final Application application) {
|
||||||
final PackageManager pm = APP.getPackageManager();
|
final PackageManager pm = application.getPackageManager();
|
||||||
final String packageName = APP.getPackageName();
|
final String packageName = application.getPackageName();
|
||||||
final int flags = PackageManager.GET_SIGNATURES;
|
final int flags = PackageManager.GET_SIGNATURES;
|
||||||
PackageInfo packageInfo = null;
|
PackageInfo packageInfo = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
packageInfo = pm.getPackageInfo(packageName, flags);
|
packageInfo = pm.getPackageInfo(packageName, flags);
|
||||||
} catch (final PackageManager.NameNotFoundException e) {
|
} catch (final PackageManager.NameNotFoundException e) {
|
||||||
ErrorActivity.reportError(APP, e, null, null,
|
ErrorActivity.reportError(application, e, null, null,
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
||||||
"Could not find package info", R.string.app_ui_crash));
|
"Could not find package info", R.string.app_ui_crash));
|
||||||
}
|
}
|
||||||
|
@ -78,7 +81,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
||||||
final CertificateFactory cf = CertificateFactory.getInstance("X509");
|
final CertificateFactory cf = CertificateFactory.getInstance("X509");
|
||||||
c = (X509Certificate) cf.generateCertificate(input);
|
c = (X509Certificate) cf.generateCertificate(input);
|
||||||
} catch (final CertificateException e) {
|
} catch (final CertificateException e) {
|
||||||
ErrorActivity.reportError(APP, e, null, null,
|
ErrorActivity.reportError(application, e, null, null,
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
||||||
"Certificate error", R.string.app_ui_crash));
|
"Certificate error", R.string.app_ui_crash));
|
||||||
}
|
}
|
||||||
|
@ -90,7 +93,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
||||||
final byte[] publicKey = md.digest(c.getEncoded());
|
final byte[] publicKey = md.digest(c.getEncoded());
|
||||||
hexString = byte2HexFormatted(publicKey);
|
hexString = byte2HexFormatted(publicKey);
|
||||||
} catch (NoSuchAlgorithmException | CertificateEncodingException e) {
|
} catch (NoSuchAlgorithmException | CertificateEncodingException e) {
|
||||||
ErrorActivity.reportError(APP, e, null, null,
|
ErrorActivity.reportError(application, e, null, null,
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
||||||
"Could not retrieve SHA1 key", R.string.app_ui_crash));
|
"Could not retrieve SHA1 key", R.string.app_ui_crash));
|
||||||
}
|
}
|
||||||
|
@ -118,104 +121,108 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
||||||
return str.toString();
|
return str.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isGithubApk() {
|
/**
|
||||||
return getCertificateSHA1Fingerprint().equals(GITHUB_APK_SHA1);
|
* Method to compare the current and latest available app version.
|
||||||
|
* If a newer version is available, we show the update notification.
|
||||||
|
*
|
||||||
|
* @param application The application
|
||||||
|
* @param versionName Name of new version
|
||||||
|
* @param apkLocationUrl Url with the new apk
|
||||||
|
* @param versionCode Code of new version
|
||||||
|
*/
|
||||||
|
private static void compareAppVersionAndShowNotification(@NonNull final Application application,
|
||||||
|
final String versionName,
|
||||||
|
final String apkLocationUrl,
|
||||||
|
final int versionCode) {
|
||||||
|
final int notificationId = 2000;
|
||||||
|
|
||||||
|
if (BuildConfig.VERSION_CODE < versionCode) {
|
||||||
|
// A pending intent to open the apk location url in the browser.
|
||||||
|
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(apkLocationUrl));
|
||||||
|
final PendingIntent pendingIntent
|
||||||
|
= PendingIntent.getActivity(application, 0, intent, 0);
|
||||||
|
|
||||||
|
final String channelId = application
|
||||||
|
.getString(R.string.app_update_notification_channel_id);
|
||||||
|
final NotificationCompat.Builder notificationBuilder
|
||||||
|
= new NotificationCompat.Builder(application, channelId)
|
||||||
|
.setSmallIcon(R.drawable.ic_newpipe_update)
|
||||||
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||||
|
.setContentIntent(pendingIntent)
|
||||||
|
.setAutoCancel(true)
|
||||||
|
.setContentTitle(application
|
||||||
|
.getString(R.string.app_update_notification_content_title))
|
||||||
|
.setContentText(application
|
||||||
|
.getString(R.string.app_update_notification_content_text)
|
||||||
|
+ " " + versionName);
|
||||||
|
|
||||||
|
final NotificationManagerCompat notificationManager
|
||||||
|
= NotificationManagerCompat.from(application);
|
||||||
|
notificationManager.notify(notificationId, notificationBuilder.build());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private static boolean isConnected(@NonNull final App app) {
|
||||||
protected void onPreExecute() {
|
final ConnectivityManager cm = ContextCompat.getSystemService(app,
|
||||||
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(APP);
|
ConnectivityManager.class);
|
||||||
|
return cm.getActiveNetworkInfo() != null
|
||||||
|
&& cm.getActiveNetworkInfo().isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isGithubApk(@NonNull final App app) {
|
||||||
|
return getCertificateSHA1Fingerprint(app).equals(GITHUB_APK_SHA1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static Disposable checkNewVersion(@NonNull final App app) {
|
||||||
|
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(app);
|
||||||
|
|
||||||
// Check if user has enabled/disabled update checking
|
// Check if user has enabled/disabled update checking
|
||||||
// and if the current apk is a github one or not.
|
// and if the current apk is a github one or not.
|
||||||
if (!prefs.getBoolean(APP.getString(R.string.update_app_key), true) || !isGithubApk()) {
|
if (!prefs.getBoolean(app.getString(R.string.update_app_key), true)
|
||||||
this.cancel(true);
|
|| !isGithubApk(app)) {
|
||||||
}
|
return Disposables.empty();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String doInBackground(final Void... voids) {
|
|
||||||
if (isCancelled() || !isConnected()) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a network request to get latest NewPipe data.
|
return Observable.fromCallable(() -> {
|
||||||
try {
|
if (!isConnected(app)) {
|
||||||
return DownloaderImpl.getInstance().get(NEWPIPE_API_URL).responseBody();
|
return null;
|
||||||
} catch (IOException | ReCaptchaException e) {
|
|
||||||
// connectivity problems, do not alarm user and fail silently
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.w(TAG, Log.getStackTraceString(e));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(final String response) {
|
|
||||||
// Parse the json from the response.
|
|
||||||
if (response != null) {
|
|
||||||
|
|
||||||
|
// Make a network request to get latest NewPipe data.
|
||||||
try {
|
try {
|
||||||
final JsonObject githubStableObject = JsonParser.object().from(response)
|
return DownloaderImpl.getInstance().get(NEWPIPE_API_URL).responseBody();
|
||||||
.getObject("flavors").getObject("github").getObject("stable");
|
} catch (IOException | ReCaptchaException e) {
|
||||||
|
|
||||||
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) {
|
|
||||||
// connectivity problems, do not alarm user and fail silently
|
// connectivity problems, do not alarm user and fail silently
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.w(TAG, Log.getStackTraceString(e));
|
Log.w(TAG, Log.getStackTraceString(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return null;
|
||||||
* Method to compare the current and latest available app version.
|
})
|
||||||
* If a newer version is available, we show the update notification.
|
.subscribeOn(Schedulers.io())
|
||||||
*
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
* @param versionName Name of new version
|
.subscribe(response -> {
|
||||||
* @param apkLocationUrl Url with the new apk
|
// Parse the json from the response.
|
||||||
* @param versionCode Code of new version
|
if (response != null) {
|
||||||
*/
|
try {
|
||||||
private void compareAppVersionAndShowNotification(final String versionName,
|
final JsonObject githubStableObject = JsonParser.object().from(response)
|
||||||
final String apkLocationUrl,
|
.getObject("flavors").getObject("github").getObject("stable");
|
||||||
final int versionCode) {
|
|
||||||
final int notificationId = 2000;
|
|
||||||
|
|
||||||
if (BuildConfig.VERSION_CODE < versionCode) {
|
final String versionName = githubStableObject.getString("version");
|
||||||
|
final int versionCode = githubStableObject.getInt("version_code");
|
||||||
|
final String apkLocationUrl = githubStableObject.getString("apk");
|
||||||
|
|
||||||
// A pending intent to open the apk location url in the browser.
|
compareAppVersionAndShowNotification(app, versionName, apkLocationUrl,
|
||||||
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(apkLocationUrl));
|
versionCode);
|
||||||
final PendingIntent pendingIntent
|
} catch (final JsonParserException e) {
|
||||||
= PendingIntent.getActivity(APP, 0, intent, 0);
|
// connectivity problems, do not alarm user and fail silently
|
||||||
|
if (DEBUG) {
|
||||||
final NotificationCompat.Builder notificationBuilder = new NotificationCompat
|
Log.w(TAG, Log.getStackTraceString(e));
|
||||||
.Builder(APP, APP.getString(R.string.app_update_notification_channel_id))
|
}
|
||||||
.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(notificationId, notificationBuilder.build());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isConnected() {
|
|
||||||
final ConnectivityManager cm = ContextCompat.getSystemService(APP,
|
|
||||||
ConnectivityManager.class);
|
|
||||||
return cm.getActiveNetworkInfo() != null
|
|
||||||
&& cm.getActiveNetworkInfo().isConnected();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,5 @@
|
||||||
package org.schabi.newpipe.about;
|
package org.schabi.newpipe.about;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
@ -21,15 +20,19 @@ import java.io.Serializable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fragment containing the software licenses.
|
* Fragment containing the software licenses.
|
||||||
*/
|
*/
|
||||||
public class LicenseFragment extends Fragment {
|
public class LicenseFragment extends Fragment {
|
||||||
private static final String ARG_COMPONENTS = "components";
|
private static final String ARG_COMPONENTS = "components";
|
||||||
|
private static final String LICENSE_KEY = "ACTIVE_LICENSE";
|
||||||
|
|
||||||
private SoftwareComponent[] softwareComponents;
|
private SoftwareComponent[] softwareComponents;
|
||||||
private SoftwareComponent componentForContextMenu;
|
private SoftwareComponent componentForContextMenu;
|
||||||
private License activeLicense;
|
private License activeLicense;
|
||||||
private static final String LICENSE_KEY = "ACTIVE_LICENSE";
|
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||||
|
|
||||||
public static LicenseFragment newInstance(final SoftwareComponent[] softwareComponents) {
|
public static LicenseFragment newInstance(final SoftwareComponent[] softwareComponents) {
|
||||||
if (softwareComponents == null) {
|
if (softwareComponents == null) {
|
||||||
|
@ -42,16 +45,6 @@ public class LicenseFragment extends Fragment {
|
||||||
return fragment;
|
return fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows a popup containing the license.
|
|
||||||
*
|
|
||||||
* @param context the context to use
|
|
||||||
* @param license the license to show
|
|
||||||
*/
|
|
||||||
private static void showLicense(final Activity context, final License license) {
|
|
||||||
new LicenseFragmentHelper(context).execute(license);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -68,6 +61,12 @@ public class LicenseFragment extends Fragment {
|
||||||
Arrays.sort(softwareComponents, Comparator.comparing(SoftwareComponent::getName));
|
Arrays.sort(softwareComponents, Comparator.comparing(SoftwareComponent::getName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
compositeDisposable.dispose();
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
|
public View onCreateView(final LayoutInflater inflater, @Nullable final ViewGroup container,
|
||||||
|
@ -77,8 +76,9 @@ public class LicenseFragment extends Fragment {
|
||||||
|
|
||||||
final View licenseLink = rootView.findViewById(R.id.app_read_license);
|
final View licenseLink = rootView.findViewById(R.id.app_read_license);
|
||||||
licenseLink.setOnClickListener(v -> {
|
licenseLink.setOnClickListener(v -> {
|
||||||
activeLicense = StandardLicenses.GPL3;
|
activeLicense = StandardLicenses.GPL3;
|
||||||
showLicense(getActivity(), StandardLicenses.GPL3);
|
compositeDisposable.add(LicenseFragmentHelper.showLicense(getActivity(),
|
||||||
|
StandardLicenses.GPL3));
|
||||||
});
|
});
|
||||||
|
|
||||||
for (final SoftwareComponent component : softwareComponents) {
|
for (final SoftwareComponent component : softwareComponents) {
|
||||||
|
@ -95,13 +95,15 @@ public class LicenseFragment extends Fragment {
|
||||||
componentView.setTag(component);
|
componentView.setTag(component);
|
||||||
componentView.setOnClickListener(v -> {
|
componentView.setOnClickListener(v -> {
|
||||||
activeLicense = component.getLicense();
|
activeLicense = component.getLicense();
|
||||||
showLicense(getActivity(), component.getLicense());
|
compositeDisposable.add(LicenseFragmentHelper.showLicense(getActivity(),
|
||||||
|
component.getLicense()));
|
||||||
});
|
});
|
||||||
softwareComponentsView.addView(componentView);
|
softwareComponentsView.addView(componentView);
|
||||||
registerForContextMenu(componentView);
|
registerForContextMenu(componentView);
|
||||||
}
|
}
|
||||||
if (activeLicense != null) {
|
if (activeLicense != null) {
|
||||||
showLicense(getActivity(), activeLicense);
|
compositeDisposable.add(LicenseFragmentHelper.showLicense(getActivity(),
|
||||||
|
activeLicense));
|
||||||
}
|
}
|
||||||
return rootView;
|
return rootView;
|
||||||
}
|
}
|
||||||
|
@ -129,7 +131,8 @@ public class LicenseFragment extends Fragment {
|
||||||
ShareUtils.openUrlInBrowser(getActivity(), component.getLink());
|
ShareUtils.openUrlInBrowser(getActivity(), component.getLink());
|
||||||
return true;
|
return true;
|
||||||
case R.id.action_show_license:
|
case R.id.action_show_license:
|
||||||
showLicense(getActivity(), component.getLicense());
|
compositeDisposable.add(LicenseFragmentHelper.showLicense(getActivity(),
|
||||||
|
component.getLicense()));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package org.schabi.newpipe.about;
|
package org.schabi.newpipe.about;
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.util.Base64;
|
import android.util.Base64;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
|
|
||||||
|
@ -16,18 +14,18 @@ import org.schabi.newpipe.util.ThemeHelper;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.disposables.Disposable;
|
||||||
|
import io.reactivex.disposables.Disposables;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
|
||||||
|
|
||||||
public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
|
public final class LicenseFragmentHelper {
|
||||||
private final WeakReference<Activity> weakReference;
|
private LicenseFragmentHelper() { }
|
||||||
private License license;
|
|
||||||
|
|
||||||
public LicenseFragmentHelper(@Nullable final Activity activity) {
|
|
||||||
weakReference = new WeakReference<>(activity);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param context the context to use
|
* @param context the context to use
|
||||||
|
@ -62,7 +60,7 @@ public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
|
||||||
* @param context
|
* @param context
|
||||||
* @return String which is a CSS stylesheet according to the context's theme
|
* @return String which is a CSS stylesheet according to the context's theme
|
||||||
*/
|
*/
|
||||||
private static String getLicenseStylesheet(final Context context) {
|
private static String getLicenseStylesheet(@NonNull final Context context) {
|
||||||
final boolean isLightTheme = ThemeHelper.isLightThemeSelected(context);
|
final boolean isLightTheme = ThemeHelper.isLightThemeSelected(context);
|
||||||
return "body{padding:12px 15px;margin:0;"
|
return "body{padding:12px 15px;margin:0;"
|
||||||
+ "background:#" + getHexRGBColor(context, isLightTheme
|
+ "background:#" + getHexRGBColor(context, isLightTheme
|
||||||
|
@ -84,45 +82,31 @@ public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
|
||||||
* @param color the color number from R.color
|
* @param color the color number from R.color
|
||||||
* @return a six characters long String with hexadecimal RGB values
|
* @return a six characters long String with hexadecimal RGB values
|
||||||
*/
|
*/
|
||||||
private static String getHexRGBColor(final Context context, final int color) {
|
private static String getHexRGBColor(@NonNull final Context context, final int color) {
|
||||||
return context.getResources().getString(color).substring(3);
|
return context.getResources().getString(color).substring(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
static Disposable showLicense(@Nullable final Context context, @NonNull final License license) {
|
||||||
private Activity getActivity() {
|
if (context == null) {
|
||||||
final Activity activity = weakReference.get();
|
return Disposables.empty();
|
||||||
|
|
||||||
if (activity != null && activity.isFinishing()) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return activity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Integer doInBackground(final Object... objects) {
|
|
||||||
license = (License) objects[0];
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(final Integer result) {
|
|
||||||
final Activity activity = getActivity();
|
|
||||||
if (activity == null) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final String webViewData = Base64.encodeToString(getFormattedLicense(activity, license)
|
return Observable.fromCallable(() -> getFormattedLicense(context, license))
|
||||||
.getBytes(StandardCharsets.UTF_8), Base64.NO_PADDING);
|
.subscribeOn(Schedulers.io())
|
||||||
final WebView webView = new WebView(activity);
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
webView.loadData(webViewData, "text/html; charset=UTF-8", "base64");
|
.subscribe(formattedLicense -> {
|
||||||
|
final String webViewData = Base64.encodeToString(formattedLicense
|
||||||
|
.getBytes(StandardCharsets.UTF_8), Base64.NO_PADDING);
|
||||||
|
final WebView webView = new WebView(context);
|
||||||
|
webView.loadData(webViewData, "text/html; charset=UTF-8", "base64");
|
||||||
|
|
||||||
final AlertDialog.Builder alert = new AlertDialog.Builder(activity);
|
final AlertDialog.Builder alert = new AlertDialog.Builder(context);
|
||||||
alert.setTitle(license.getName());
|
alert.setTitle(license.getName());
|
||||||
alert.setView(webView);
|
alert.setView(webView);
|
||||||
assureCorrectAppLanguage(activity);
|
assureCorrectAppLanguage(context);
|
||||||
alert.setNegativeButton(activity.getString(R.string.finish),
|
alert.setNegativeButton(context.getString(R.string.finish),
|
||||||
(dialog, which) -> dialog.dismiss());
|
(dialog, which) -> dialog.dismiss());
|
||||||
alert.show();
|
alert.show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,8 @@ import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
import org.schabi.newpipe.CheckForNewAppVersionTask;
|
import org.schabi.newpipe.App;
|
||||||
|
import org.schabi.newpipe.CheckForNewAppVersion;
|
||||||
import org.schabi.newpipe.MainActivity;
|
import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
|
@ -15,7 +16,7 @@ public class MainSettingsFragment extends BasePreferenceFragment {
|
||||||
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
||||||
addPreferencesFromResource(R.xml.main_settings);
|
addPreferencesFromResource(R.xml.main_settings);
|
||||||
|
|
||||||
if (!CheckForNewAppVersionTask.isGithubApk()) {
|
if (!CheckForNewAppVersion.isGithubApk(App.getApp())) {
|
||||||
final Preference update = findPreference(getString(R.string.update_pref_screen_key));
|
final Preference update = findPreference(getString(R.string.update_pref_screen_key));
|
||||||
getPreferenceScreen().removePreference(update);
|
getPreferenceScreen().removePreference(update);
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package us.shandian.giga.ui.adapter;
|
package us.shandian.giga.ui.adapter;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.ProgressDialog;
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.AsyncTask;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
@ -26,7 +24,6 @@ import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.annotation.StringRes;
|
import androidx.annotation.StringRes;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.core.content.FileProvider;
|
import androidx.core.content.FileProvider;
|
||||||
|
@ -46,12 +43,15 @@ import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.NavigationHelper;
|
import org.schabi.newpipe.util.NavigationHelper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
import us.shandian.giga.get.DownloadMission;
|
import us.shandian.giga.get.DownloadMission;
|
||||||
import us.shandian.giga.get.FinishedMission;
|
import us.shandian.giga.get.FinishedMission;
|
||||||
import us.shandian.giga.get.Mission;
|
import us.shandian.giga.get.Mission;
|
||||||
|
@ -116,6 +116,8 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
||||||
private final Runnable rUpdater = this::updater;
|
private final Runnable rUpdater = this::updater;
|
||||||
private final Runnable rDelete = this::deleteFinishedDownloads;
|
private final Runnable rDelete = this::deleteFinishedDownloads;
|
||||||
|
|
||||||
|
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
|
||||||
|
|
||||||
public MissionAdapter(Context context, @NonNull DownloadManager downloadManager, View emptyMessage, View root) {
|
public MissionAdapter(Context context, @NonNull DownloadManager downloadManager, View emptyMessage, View root) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mDownloadManager = downloadManager;
|
mDownloadManager = downloadManager;
|
||||||
|
@ -675,7 +677,30 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
||||||
return true;
|
return true;
|
||||||
case R.id.md5:
|
case R.id.md5:
|
||||||
case R.id.sha1:
|
case R.id.sha1:
|
||||||
new ChecksumTask(mContext).execute(h.item.mission.storage, ALGORITHMS.get(id));
|
ProgressDialog progressDialog = null;
|
||||||
|
if (mContext != null) {
|
||||||
|
// Create dialog
|
||||||
|
progressDialog = new ProgressDialog(mContext);
|
||||||
|
progressDialog.setCancelable(false);
|
||||||
|
progressDialog.setMessage(mContext.getString(R.string.msg_wait));
|
||||||
|
progressDialog.show();
|
||||||
|
}
|
||||||
|
final ProgressDialog finalProgressDialog = progressDialog;
|
||||||
|
final StoredFileHelper storage = h.item.mission.storage;
|
||||||
|
compositeDisposable.add(
|
||||||
|
Observable.fromCallable(() -> Utility.checksum(storage, ALGORITHMS.get(id)))
|
||||||
|
.subscribeOn(Schedulers.computation())
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe(result -> {
|
||||||
|
if (finalProgressDialog != null) {
|
||||||
|
Utility.copyToClipboard(finalProgressDialog.getContext(),
|
||||||
|
result);
|
||||||
|
if (mContext != null) {
|
||||||
|
finalProgressDialog.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
case R.id.source:
|
case R.id.source:
|
||||||
/*Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(h.item.mission.source));
|
/*Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(h.item.mission.source));
|
||||||
|
@ -758,8 +783,8 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void onDestroy() {
|
public void onDestroy() {
|
||||||
|
compositeDisposable.dispose();
|
||||||
mDeleter.dispose();
|
mDeleter.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -960,60 +985,7 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static class ChecksumTask extends AsyncTask<Object, Void, String> {
|
|
||||||
ProgressDialog progressDialog;
|
|
||||||
WeakReference<Activity> weakReference;
|
|
||||||
|
|
||||||
ChecksumTask(@NonNull Context context) {
|
|
||||||
weakReference = new WeakReference<>((Activity) context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPreExecute() {
|
|
||||||
super.onPreExecute();
|
|
||||||
|
|
||||||
Activity activity = getActivity();
|
|
||||||
if (activity != null) {
|
|
||||||
// Create dialog
|
|
||||||
progressDialog = new ProgressDialog(activity);
|
|
||||||
progressDialog.setCancelable(false);
|
|
||||||
progressDialog.setMessage(activity.getString(R.string.msg_wait));
|
|
||||||
progressDialog.show();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String doInBackground(Object... params) {
|
|
||||||
return Utility.checksum((StoredFileHelper) params[0], (String) params[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onPostExecute(String result) {
|
|
||||||
super.onPostExecute(result);
|
|
||||||
|
|
||||||
if (progressDialog != null) {
|
|
||||||
Utility.copyToClipboard(progressDialog.getContext(), result);
|
|
||||||
if (getActivity() != null) {
|
|
||||||
progressDialog.dismiss();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Activity getActivity() {
|
|
||||||
Activity activity = weakReference.get();
|
|
||||||
|
|
||||||
if (activity != null && activity.isFinishing()) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return activity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface RecoverHelper {
|
public interface RecoverHelper {
|
||||||
void tryRecover(DownloadMission mission);
|
void tryRecover(DownloadMission mission);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue