diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java deleted file mode 100644 index cf41aad46..000000000 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ /dev/null @@ -1,285 +0,0 @@ -package org.schabi.newpipe; - -import android.app.Application; -import android.content.Context; -import android.content.SharedPreferences; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.core.app.NotificationChannelCompat; -import androidx.core.app.NotificationManagerCompat; -import androidx.preference.PreferenceManager; - -import com.jakewharton.processphoenix.ProcessPhoenix; - -import org.acra.ACRA; -import org.acra.config.CoreConfigurationBuilder; -import org.schabi.newpipe.error.ReCaptchaActivity; -import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.downloader.Downloader; -import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor; -import org.schabi.newpipe.ktx.ExceptionUtils; -import org.schabi.newpipe.settings.NewPipeSettings; -import org.schabi.newpipe.util.BridgeStateSaverInitializer; -import org.schabi.newpipe.util.Localization; -import org.schabi.newpipe.util.ServiceHelper; -import org.schabi.newpipe.util.StateSaver; -import org.schabi.newpipe.util.image.ImageStrategy; -import org.schabi.newpipe.util.image.PicassoHelper; -import org.schabi.newpipe.util.image.PreferredImageQuality; -import org.schabi.newpipe.util.potoken.PoTokenProviderImpl; - -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.SocketException; -import java.util.List; -import java.util.Objects; - -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; - -/* - * Copyright (C) Hans-Christoph Steiner 2016 - * App.java is part of NewPipe. - * - * NewPipe is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * NewPipe is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with NewPipe. If not, see . - */ - -public class App extends Application { - public static final String PACKAGE_NAME = BuildConfig.APPLICATION_ID; - private static final String TAG = App.class.toString(); - - private boolean isFirstRun = false; - private boolean notificationsRequested = false; - - private static App app; - - @NonNull - public static App getApp() { - return app; - } - - public boolean getNotificationsRequested() { - return notificationsRequested; - } - - public void setNotificationsRequested() { - notificationsRequested = true; - } - - @Override - protected void attachBaseContext(final Context base) { - super.attachBaseContext(base); - initACRA(); - } - - @Override - public void onCreate() { - super.onCreate(); - - app = this; - - if (ProcessPhoenix.isPhoenixProcess(this)) { - Log.i(TAG, "This is a phoenix process! " - + "Aborting initialization of App[onCreate]"); - return; - } - - // check if the last used preference version is set - // to determine whether this is the first app run - final int lastUsedPrefVersion = PreferenceManager.getDefaultSharedPreferences(this) - .getInt(getString(R.string.last_used_preferences_version), -1); - isFirstRun = lastUsedPrefVersion == -1; - - // Initialize settings first because other initializations can use its values - NewPipeSettings.initSettings(this); - - NewPipe.init(getDownloader(), - Localization.getPreferredLocalization(this), - Localization.getPreferredContentCountry(this)); - Localization.initPrettyTime(Localization.resolvePrettyTime()); - - BridgeStateSaverInitializer.init(this); - StateSaver.init(this); - initNotificationChannels(); - - ServiceHelper.initServices(this); - - // Initialize image loader - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - PicassoHelper.init(this); - ImageStrategy.setPreferredImageQuality(PreferredImageQuality.fromPreferenceKey(this, - prefs.getString(getString(R.string.image_quality_key), - getString(R.string.image_quality_default)))); - PicassoHelper.setIndicatorsEnabled(MainActivity.DEBUG - && prefs.getBoolean(getString(R.string.show_image_indicators_key), false)); - - configureRxJavaErrorHandler(); - - YoutubeStreamExtractor.setPoTokenProvider(PoTokenProviderImpl.INSTANCE); - } - - @Override - public void onTerminate() { - super.onTerminate(); - PicassoHelper.terminate(); - } - - protected Downloader getDownloader() { - final DownloaderImpl downloader = DownloaderImpl.init(null); - setCookiesToDownloader(downloader); - return downloader; - } - - protected void setCookiesToDownloader(final DownloaderImpl downloader) { - final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( - getApplicationContext()); - final String key = getApplicationContext().getString(R.string.recaptcha_cookies_key); - downloader.setCookie(ReCaptchaActivity.RECAPTCHA_COOKIES_KEY, prefs.getString(key, null)); - downloader.updateYoutubeRestrictedModeCookies(getApplicationContext()); - } - - private void configureRxJavaErrorHandler() { - // https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling - RxJavaPlugins.setErrorHandler(new Consumer() { - @Override - public void accept(@NonNull final Throwable throwable) { - Log.e(TAG, "RxJavaPlugins.ErrorHandler called with -> : " - + "throwable = [" + throwable.getClass().getName() + "]"); - - final Throwable actualThrowable; - if (throwable instanceof UndeliverableException) { - // As UndeliverableException is a wrapper, - // get the cause of it to get the "real" exception - actualThrowable = Objects.requireNonNull(throwable.getCause()); - } else { - actualThrowable = throwable; - } - - final List errors; - if (actualThrowable instanceof CompositeException) { - errors = ((CompositeException) actualThrowable).getExceptions(); - } else { - errors = List.of(actualThrowable); - } - - for (final Throwable error : errors) { - if (isThrowableIgnored(error)) { - return; - } - if (isThrowableCritical(error)) { - reportException(error); - return; - } - } - - // Out-of-lifecycle exceptions should only be reported if a debug user wishes so, - // When exception is not reported, log it - if (isDisposedRxExceptionsReported()) { - reportException(actualThrowable); - } else { - Log.e(TAG, "RxJavaPlugin: Undeliverable Exception received: ", actualThrowable); - } - } - - private boolean isThrowableIgnored(@NonNull final Throwable throwable) { - // Don't crash the application over a simple network problem - return ExceptionUtils.hasAssignableCause(throwable, - // network api cancellation - IOException.class, SocketException.class, - // blocking code disposed - InterruptedException.class, InterruptedIOException.class); - } - - private boolean isThrowableCritical(@NonNull final Throwable throwable) { - // Though these exceptions cannot be ignored - return ExceptionUtils.hasAssignableCause(throwable, - NullPointerException.class, IllegalArgumentException.class, // bug in app - OnErrorNotImplementedException.class, MissingBackpressureException.class, - IllegalStateException.class); // bug in operator - } - - private void reportException(@NonNull final Throwable throwable) { - // Throw uncaught exception that will trigger the report system - Thread.currentThread().getUncaughtExceptionHandler() - .uncaughtException(Thread.currentThread(), throwable); - } - }); - } - - /** - * Called in {@link #attachBaseContext(Context)} after calling the {@code super} method. - * Should be overridden if MultiDex is enabled, since it has to be initialized before ACRA. - */ - protected void initACRA() { - if (ACRA.isACRASenderServiceProcess()) { - return; - } - - final CoreConfigurationBuilder acraConfig = new CoreConfigurationBuilder() - .withBuildConfigClass(BuildConfig.class); - ACRA.init(this, acraConfig); - } - - private void initNotificationChannels() { - // Keep the importance below DEFAULT to avoid making noise on every notification update for - // the main and update channels - final List notificationChannelCompats = List.of( - new NotificationChannelCompat.Builder(getString(R.string.notification_channel_id), - NotificationManagerCompat.IMPORTANCE_LOW) - .setName(getString(R.string.notification_channel_name)) - .setDescription(getString(R.string.notification_channel_description)) - .build(), - new NotificationChannelCompat - .Builder(getString(R.string.app_update_notification_channel_id), - NotificationManagerCompat.IMPORTANCE_LOW) - .setName(getString(R.string.app_update_notification_channel_name)) - .setDescription( - getString(R.string.app_update_notification_channel_description)) - .build(), - new NotificationChannelCompat.Builder(getString(R.string.hash_channel_id), - NotificationManagerCompat.IMPORTANCE_HIGH) - .setName(getString(R.string.hash_channel_name)) - .setDescription(getString(R.string.hash_channel_description)) - .build(), - new NotificationChannelCompat.Builder(getString(R.string.error_report_channel_id), - NotificationManagerCompat.IMPORTANCE_LOW) - .setName(getString(R.string.error_report_channel_name)) - .setDescription(getString(R.string.error_report_channel_description)) - .build(), - new NotificationChannelCompat - .Builder(getString(R.string.streams_notification_channel_id), - NotificationManagerCompat.IMPORTANCE_DEFAULT) - .setName(getString(R.string.streams_notification_channel_name)) - .setDescription( - getString(R.string.streams_notification_channel_description)) - .build() - ); - - final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); - notificationManager.createNotificationChannelsCompat(notificationChannelCompats); - } - - protected boolean isDisposedRxExceptionsReported() { - return false; - } - - public boolean isFirstRun() { - return isFirstRun; - } -} diff --git a/app/src/main/java/org/schabi/newpipe/App.kt b/app/src/main/java/org/schabi/newpipe/App.kt new file mode 100644 index 000000000..ad6b82435 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/App.kt @@ -0,0 +1,285 @@ +package org.schabi.newpipe + +import android.app.Application +import android.content.Context +import android.util.Log +import androidx.core.app.NotificationChannelCompat +import androidx.core.app.NotificationManagerCompat +import androidx.preference.PreferenceManager +import com.jakewharton.processphoenix.ProcessPhoenix +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 java.io.IOException +import java.io.InterruptedIOException +import java.net.SocketException +import org.acra.ACRA.init +import org.acra.ACRA.isACRASenderServiceProcess +import org.acra.config.CoreConfigurationBuilder +import org.schabi.newpipe.error.ReCaptchaActivity +import org.schabi.newpipe.extractor.NewPipe +import org.schabi.newpipe.extractor.downloader.Downloader +import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor +import org.schabi.newpipe.ktx.hasAssignableCause +import org.schabi.newpipe.settings.NewPipeSettings +import org.schabi.newpipe.util.BridgeStateSaverInitializer +import org.schabi.newpipe.util.Localization +import org.schabi.newpipe.util.ServiceHelper +import org.schabi.newpipe.util.StateSaver +import org.schabi.newpipe.util.image.ImageStrategy.setPreferredImageQuality +import org.schabi.newpipe.util.image.PicassoHelper +import org.schabi.newpipe.util.image.PreferredImageQuality.Companion.fromPreferenceKey +import org.schabi.newpipe.util.potoken.PoTokenProviderImpl + +/* + * Copyright (C) Hans-Christoph Steiner 2016 + * App.kt is part of NewPipe. + * + * NewPipe is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NewPipe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NewPipe. If not, see . + */ +open class App : Application() { + var isFirstRun = false + private set + var notificationsRequested = false + private set + + fun setNotificationsRequested() { + notificationsRequested = true + } + + override fun attachBaseContext(base: Context?) { + super.attachBaseContext(base) + initACRA() + } + + override fun onCreate() { + super.onCreate() + + instance = this + + if (ProcessPhoenix.isPhoenixProcess(this)) { + Log.i(TAG, "This is a phoenix process! Aborting initialization of App[onCreate]") + return + } + + // check if the last used preference version is set + // to determine whether this is the first app run + val lastUsedPrefVersion = + PreferenceManager + .getDefaultSharedPreferences(this) + .getInt(getString(R.string.last_used_preferences_version), -1) + isFirstRun = lastUsedPrefVersion == -1 + + // Initialize settings first because other initializations can use its values + NewPipeSettings.initSettings(this) + + NewPipe.init( + getDownloader(), + Localization.getPreferredLocalization(this), + Localization.getPreferredContentCountry(this) + ) + Localization.initPrettyTime(Localization.resolvePrettyTime()) + + BridgeStateSaverInitializer.init(this) + StateSaver.init(this) + initNotificationChannels() + + ServiceHelper.initServices(this) + + // Initialize image loader + val prefs = PreferenceManager.getDefaultSharedPreferences(this) + PicassoHelper.init(this) + setPreferredImageQuality( + fromPreferenceKey( + this, + prefs.getString( + getString(R.string.image_quality_key), + getString(R.string.image_quality_default) + ) + ) + ) + PicassoHelper.setIndicatorsEnabled( + MainActivity.DEBUG && + prefs.getBoolean(getString(R.string.show_image_indicators_key), false) + ) + + configureRxJavaErrorHandler() + + YoutubeStreamExtractor.setPoTokenProvider(PoTokenProviderImpl) + } + + override fun onTerminate() { + super.onTerminate() + PicassoHelper.terminate() + } + + protected open fun getDownloader(): Downloader { + val downloader = DownloaderImpl.init(null) + setCookiesToDownloader(downloader) + return downloader + } + + protected fun setCookiesToDownloader(downloader: DownloaderImpl) { + val prefs = PreferenceManager.getDefaultSharedPreferences(this) + val key = getString(R.string.recaptcha_cookies_key) + downloader.setCookie(ReCaptchaActivity.RECAPTCHA_COOKIES_KEY, prefs.getString(key, null)) + downloader.updateYoutubeRestrictedModeCookies(this) + } + + private fun configureRxJavaErrorHandler() { + // https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling + RxJavaPlugins.setErrorHandler( + object : Consumer { + override fun accept(throwable: Throwable) { + Log.e(TAG, "RxJavaPlugins.ErrorHandler called with -> : throwable = [${throwable.javaClass.getName()}]") + + // As UndeliverableException is a wrapper, + // get the cause of it to get the "real" exception + val actualThrowable = (throwable as? UndeliverableException)?.cause ?: throwable + + val errors = (actualThrowable as? CompositeException)?.exceptions ?: listOf(actualThrowable) + + for (error in errors) { + if (isThrowableIgnored(error)) { + return + } + if (isThrowableCritical(error)) { + reportException(error) + return + } + } + + // Out-of-lifecycle exceptions should only be reported if a debug user wishes so, + // When exception is not reported, log it + if (isDisposedRxExceptionsReported()) { + reportException(actualThrowable) + } else { + Log.e(TAG, "RxJavaPlugin: Undeliverable Exception received: ", actualThrowable) + } + } + + fun isThrowableIgnored(throwable: Throwable): Boolean { + // Don't crash the application over a simple network problem + return throwable // network api cancellation + .hasAssignableCause( + IOException::class.java, + SocketException::class.java, // blocking code disposed + InterruptedException::class.java, + InterruptedIOException::class.java + ) + } + + fun isThrowableCritical(throwable: Throwable): Boolean { + // Though these exceptions cannot be ignored + return throwable + .hasAssignableCause( + // bug in app + NullPointerException::class.java, + IllegalArgumentException::class.java, + OnErrorNotImplementedException::class.java, + MissingBackpressureException::class.java, + // bug in operator + IllegalStateException::class.java + ) + } + + fun reportException(throwable: Throwable) { + // Throw uncaught exception that will trigger the report system + Thread + .currentThread() + .uncaughtExceptionHandler + .uncaughtException(Thread.currentThread(), throwable) + } + } + ) + } + + /** + * Called in [.attachBaseContext] after calling the `super` method. + * Should be overridden if MultiDex is enabled, since it has to be initialized before ACRA. + */ + protected fun initACRA() { + if (isACRASenderServiceProcess()) { + return + } + + val acraConfig = + CoreConfigurationBuilder() + .withBuildConfigClass(BuildConfig::class.java) + init(this, acraConfig) + } + + private fun initNotificationChannels() { + // Keep the importance below DEFAULT to avoid making noise on every notification update for + // the main and update channels + val mainChannel = + NotificationChannelCompat + .Builder( + getString(R.string.notification_channel_id), + NotificationManagerCompat.IMPORTANCE_LOW + ).setName(getString(R.string.notification_channel_name)) + .setDescription(getString(R.string.notification_channel_description)) + .build() + val appUpdateChannel = + NotificationChannelCompat + .Builder( + getString(R.string.app_update_notification_channel_id), + NotificationManagerCompat.IMPORTANCE_LOW + ).setName(getString(R.string.app_update_notification_channel_name)) + .setDescription(getString(R.string.app_update_notification_channel_description)) + .build() + val hashChannel = + NotificationChannelCompat + .Builder( + getString(R.string.hash_channel_id), + NotificationManagerCompat.IMPORTANCE_HIGH + ).setName(getString(R.string.hash_channel_name)) + .setDescription(getString(R.string.hash_channel_description)) + .build() + val errorReportChannel = + NotificationChannelCompat + .Builder( + getString(R.string.error_report_channel_id), + NotificationManagerCompat.IMPORTANCE_LOW + ).setName(getString(R.string.error_report_channel_name)) + .setDescription(getString(R.string.error_report_channel_description)) + .build() + val newStreamChannel = + NotificationChannelCompat + .Builder( + getString(R.string.streams_notification_channel_id), + NotificationManagerCompat.IMPORTANCE_DEFAULT + ).setName(getString(R.string.streams_notification_channel_name)) + .setDescription(getString(R.string.streams_notification_channel_description)) + .build() + + val channels = listOf(mainChannel, appUpdateChannel, hashChannel, errorReportChannel, newStreamChannel) + + NotificationManagerCompat.from(this).createNotificationChannelsCompat(channels) + } + + protected open fun isDisposedRxExceptionsReported(): Boolean = false + + companion object { + const val PACKAGE_NAME: String = BuildConfig.APPLICATION_ID + private val TAG = App::class.java.toString() + + @JvmStatic + lateinit var instance: App + private set + } +} diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index 3c0018d99..e4f4b5b8a 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -191,7 +191,7 @@ public class MainActivity extends AppCompatActivity { NotificationWorker.initialize(this); } if (!UpdateSettingsFragment.wasUserAskedForConsent(this) - && !App.getApp().isFirstRun() + && !App.getInstance().isFirstRun() && ReleaseVersionUtil.INSTANCE.isReleaseApk()) { UpdateSettingsFragment.askForConsentToUpdateChecks(this); } @@ -203,7 +203,7 @@ public class MainActivity extends AppCompatActivity { protected void onPostCreate(final Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); - final App app = App.getApp(); + final App app = App.getInstance(); if (sharedPreferences.getBoolean(app.getString(R.string.update_app_key), false) && sharedPreferences diff --git a/app/src/main/java/org/schabi/newpipe/info_list/dialog/InfoItemDialog.java b/app/src/main/java/org/schabi/newpipe/info_list/dialog/InfoItemDialog.java index 0c69557bf..dcf01e190 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/dialog/InfoItemDialog.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/dialog/InfoItemDialog.java @@ -346,7 +346,7 @@ public final class InfoItemDialog { public static void reportErrorDuringInitialization(final Throwable throwable, final InfoItem item) { - ErrorUtil.showSnackbar(App.getApp().getBaseContext(), new ErrorInfo( + ErrorUtil.showSnackbar(App.getInstance().getBaseContext(), new ErrorInfo( throwable, UserAction.OPEN_INFO_ITEM_DIALOG, "none", diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt index 58ec818f3..19adf6eaa 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/FeedViewModel.kt @@ -166,7 +166,7 @@ class FeedViewModel( fun getFactory(context: Context, groupId: Long) = viewModelFactory { initializer { FeedViewModel( - App.getApp(), + App.instance, groupId, // Read initial value from preferences getShowPlayedItemsFromPreferences(context.applicationContext), diff --git a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java index 9edfc804a..daae6d54e 100644 --- a/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java +++ b/app/src/main/java/org/schabi/newpipe/player/helper/PlayerHolder.java @@ -117,7 +117,7 @@ public final class PlayerHolder { // helper to handle context in common place as using the same // context to bind/unbind a service is crucial private Context getCommonContext() { - return App.getApp(); + return App.getInstance(); } public void startService(final boolean playAfterConnect, diff --git a/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java b/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java index 7cb1564b3..3cc29afee 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java +++ b/app/src/main/java/org/schabi/newpipe/settings/NewPipeSettings.java @@ -157,7 +157,7 @@ public final class NewPipeSettings { prefs.getInt(disabledTunnelingAutomaticallyKey, -1) == 0 && !prefs.getBoolean(disabledTunnelingKey, false); - if (App.getApp().isFirstRun() + if (App.getInstance().isFirstRun() || (wasDeviceBlacklistUpdated && !wasMediaTunnelingEnabledByUser)) { setMediaTunneling(context); } diff --git a/app/src/main/java/org/schabi/newpipe/settings/migration/SettingMigrations.java b/app/src/main/java/org/schabi/newpipe/settings/migration/SettingMigrations.java index 67944075d..92520ec7e 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/migration/SettingMigrations.java +++ b/app/src/main/java/org/schabi/newpipe/settings/migration/SettingMigrations.java @@ -251,7 +251,7 @@ public final class SettingMigrations { final int lastPrefVersion = sp.getInt(lastPrefVersionKey, 0); // no migration to run, already up to date - if (App.getApp().isFirstRun()) { + if (App.getInstance().isFirstRun()) { sp.edit().putInt(lastPrefVersionKey, VERSION).apply(); return; } else if (lastPrefVersion == VERSION) { diff --git a/app/src/main/java/org/schabi/newpipe/util/DeviceUtils.java b/app/src/main/java/org/schabi/newpipe/util/DeviceUtils.java index 9eb9fab37..83152a36d 100644 --- a/app/src/main/java/org/schabi/newpipe/util/DeviceUtils.java +++ b/app/src/main/java/org/schabi/newpipe/util/DeviceUtils.java @@ -131,7 +131,7 @@ public final class DeviceUtils { } isFireTV = - App.getApp().getPackageManager().hasSystemFeature(AMAZON_FEATURE_FIRE_TV); + App.getInstance().getPackageManager().hasSystemFeature(AMAZON_FEATURE_FIRE_TV); return isFireTV; } @@ -140,7 +140,7 @@ public final class DeviceUtils { return isTV; } - final PackageManager pm = App.getApp().getPackageManager(); + final PackageManager pm = App.getInstance().getPackageManager(); // from doc: https://developer.android.com/training/tv/start/hardware.html#runtime-check boolean isTv = ContextCompat.getSystemService(context, UiModeManager.class) diff --git a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java index 969d787d7..2defbdc5b 100644 --- a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java @@ -90,10 +90,10 @@ public final class PermissionHelper { && ContextCompat.checkSelfPermission(activity, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { - if (!App.getApp().getNotificationsRequested()) { + if (!App.getInstance().getNotificationsRequested()) { ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.POST_NOTIFICATIONS}, requestCode); - App.getApp().setNotificationsRequested(); + App.getInstance().setNotificationsRequested(); return false; } } diff --git a/app/src/main/java/org/schabi/newpipe/util/ReleaseVersionUtil.kt b/app/src/main/java/org/schabi/newpipe/util/ReleaseVersionUtil.kt index bc3849384..31d42d751 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ReleaseVersionUtil.kt +++ b/app/src/main/java/org/schabi/newpipe/util/ReleaseVersionUtil.kt @@ -21,7 +21,7 @@ object ReleaseVersionUtil { val certificates = mapOf( RELEASE_CERT_PUBLIC_KEY_SHA256.hexToByteArray() to PackageManager.CERT_INPUT_SHA256 ) - val app = App.getApp() + val app = App.instance try { PackageInfoCompat.hasSignatures(app.packageManager, app.packageName, certificates, false) } catch (e: PackageManager.NameNotFoundException) { diff --git a/app/src/main/java/org/schabi/newpipe/util/potoken/PoTokenProviderImpl.kt b/app/src/main/java/org/schabi/newpipe/util/potoken/PoTokenProviderImpl.kt index 12fadb68d..53ae04a3c 100644 --- a/app/src/main/java/org/schabi/newpipe/util/potoken/PoTokenProviderImpl.kt +++ b/app/src/main/java/org/schabi/newpipe/util/potoken/PoTokenProviderImpl.kt @@ -78,7 +78,7 @@ object PoTokenProviderImpl : PoTokenProvider { // create a new webPoTokenGenerator webPoTokenGenerator = PoTokenWebView - .newPoTokenGenerator(App.getApp()).blockingGet() + .newPoTokenGenerator(App.instance).blockingGet() // The streaming poToken needs to be generated exactly once before generating // any other (player) tokens.