diff --git a/app/build.gradle b/app/build.gradle index 993363e32..d6b49f232 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,7 +12,7 @@ plugins { } android { - compileSdk 33 + compileSdk 34 namespace 'org.schabi.newpipe' defaultConfig { @@ -106,9 +106,9 @@ android { ext { checkstyleVersion = '10.12.1' - androidxLifecycleVersion = '2.5.1' + androidxLifecycleVersion = '2.6.2' androidxRoomVersion = '2.5.2' - androidxWorkVersion = '2.7.1' + androidxWorkVersion = '2.8.1' icepickVersion = '3.2.0' exoPlayerVersion = '2.18.7' @@ -208,25 +208,25 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}" /** AndroidX **/ - implementation 'androidx.appcompat:appcompat:1.5.1' + implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.core:core-ktx:1.10.0' + implementation 'androidx.core:core-ktx:1.12.0' implementation 'androidx.documentfile:documentfile:1.0.1' - implementation 'androidx.fragment:fragment-ktx:1.4.1' + implementation 'androidx.fragment:fragment-ktx:1.6.1' implementation "androidx.lifecycle:lifecycle-livedata-ktx:${androidxLifecycleVersion}" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${androidxLifecycleVersion}" implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.1.0' implementation 'androidx.media:media:1.6.0' - implementation 'androidx.preference:preference:1.2.0' - implementation 'androidx.recyclerview:recyclerview:1.2.1' + implementation 'androidx.preference:preference:1.2.1' + implementation 'androidx.recyclerview:recyclerview:1.3.2' implementation "androidx.room:room-runtime:${androidxRoomVersion}" implementation "androidx.room:room-rxjava3:${androidxRoomVersion}" kapt "androidx.room:room-compiler:${androidxRoomVersion}" implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' // Newer version specified to prevent accessibility regressions with RecyclerView, see: // https://developer.android.com/jetpack/androidx/releases/viewpager2#1.1.0-alpha01 - implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01' + implementation 'androidx.viewpager2:viewpager2:1.1.0-beta02' implementation "androidx.work:work-runtime-ktx:${androidxWorkVersion}" implementation "androidx.work:work-rxjava3:${androidxWorkVersion}" implementation 'com.google.android.material:material:1.9.0' diff --git a/app/src/main/java/androidx/fragment/app/FragmentStatePagerAdapterMenuWorkaround.java b/app/src/main/java/androidx/fragment/app/FragmentStatePagerAdapterMenuWorkaround.java index 8d87e90bd..8d03a1486 100644 --- a/app/src/main/java/androidx/fragment/app/FragmentStatePagerAdapterMenuWorkaround.java +++ b/app/src/main/java/androidx/fragment/app/FragmentStatePagerAdapterMenuWorkaround.java @@ -25,6 +25,7 @@ import android.view.ViewGroup; import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.os.BundleCompat; import androidx.lifecycle.Lifecycle; import androidx.viewpager.widget.PagerAdapter; @@ -284,7 +285,7 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt Bundle state = null; if (!mSavedState.isEmpty()) { state = new Bundle(); - state.putParcelableArray("states", mSavedState.toArray(new Fragment.SavedState[0])); + state.putParcelableArrayList("states", mSavedState); } for (int i = 0; i < mFragments.size(); i++) { final Fragment f = mFragments.get(i); @@ -311,13 +312,12 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt if (state != null) { final Bundle bundle = (Bundle) state; bundle.setClassLoader(loader); - final Parcelable[] fss = bundle.getParcelableArray("states"); + final var states = BundleCompat.getParcelableArrayList(bundle, "states", + Fragment.SavedState.class); mSavedState.clear(); mFragments.clear(); - if (fss != null) { - for (final Parcelable parcelable : fss) { - mSavedState.add((Fragment.SavedState) parcelable); - } + if (states != null) { + mSavedState.addAll(states); } final Iterable keys = bundle.keySet(); for (final String key : keys) { diff --git a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.kt b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.kt index f1d4c26df..7f148e9b5 100644 --- a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.kt +++ b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.kt @@ -116,7 +116,7 @@ class AboutActivity : AppCompatActivity() { /** * List of all software components. */ - private val SOFTWARE_COMPONENTS = arrayOf( + private val SOFTWARE_COMPONENTS = arrayListOf( SoftwareComponent( "ACRA", "2013", "Kevin Gaudin", "https://github.com/ACRA/acra", StandardLicenses.APACHE2 diff --git a/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.kt b/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.kt index a5cf2924a..9f5ad2a7a 100644 --- a/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.kt @@ -18,6 +18,7 @@ import org.schabi.newpipe.BuildConfig import org.schabi.newpipe.R import org.schabi.newpipe.databinding.FragmentLicensesBinding import org.schabi.newpipe.databinding.ItemSoftwareComponentBinding +import org.schabi.newpipe.ktx.parcelableArrayList import org.schabi.newpipe.util.Localization import org.schabi.newpipe.util.external_communication.ShareUtils @@ -25,16 +26,15 @@ import org.schabi.newpipe.util.external_communication.ShareUtils * Fragment containing the software licenses. */ class LicenseFragment : Fragment() { - private lateinit var softwareComponents: Array + private lateinit var softwareComponents: List private var activeSoftwareComponent: SoftwareComponent? = null private val compositeDisposable = CompositeDisposable() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - softwareComponents = arguments?.getParcelableArray(ARG_COMPONENTS) as Array + softwareComponents = arguments?.parcelableArrayList(ARG_COMPONENTS)!! + .sortedBy { it.name } // Sort components by name activeSoftwareComponent = savedInstanceState?.getSerializable(SOFTWARE_COMPONENT_KEY) as? SoftwareComponent - // Sort components by name - softwareComponents.sortBy { it.name } } override fun onDestroy() { @@ -130,7 +130,8 @@ class LicenseFragment : Fragment() { StandardLicenses.GPL3, BuildConfig.VERSION_NAME ) - fun newInstance(softwareComponents: Array): LicenseFragment { + + fun newInstance(softwareComponents: ArrayList): LicenseFragment { val fragment = LicenseFragment() fragment.arguments = bundleOf(ARG_COMPONENTS to softwareComponents) return fragment diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java index 2e0a421da..1375d661e 100644 --- a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java @@ -74,6 +74,7 @@ import org.schabi.newpipe.util.ThemeHelper; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.Objects; @@ -1052,7 +1053,7 @@ public class DownloadDialog extends DialogFragment final char kind; int threads = dialogBinding.threads.getProgress() + 1; final String[] urls; - final MissionRecoveryInfo[] recoveryInfo; + final List recoveryInfo; String psName = null; String[] psArgs = null; long nearLength = 0; @@ -1117,9 +1118,7 @@ public class DownloadDialog extends DialogFragment urls = new String[] { selectedStream.getContent() }; - recoveryInfo = new MissionRecoveryInfo[] { - new MissionRecoveryInfo(selectedStream) - }; + recoveryInfo = List.of(new MissionRecoveryInfo(selectedStream)); } else { if (secondaryStream.getDeliveryMethod() != PROGRESSIVE_HTTP) { throw new IllegalArgumentException("Unsupported stream delivery format" @@ -1129,12 +1128,14 @@ public class DownloadDialog extends DialogFragment urls = new String[] { selectedStream.getContent(), secondaryStream.getContent() }; - recoveryInfo = new MissionRecoveryInfo[] {new MissionRecoveryInfo(selectedStream), - new MissionRecoveryInfo(secondaryStream)}; + recoveryInfo = List.of( + new MissionRecoveryInfo(selectedStream), + new MissionRecoveryInfo(secondaryStream) + ); } DownloadManagerService.startMission(context, urls, storage, kind, threads, - currentInfo.getUrl(), psName, psArgs, nearLength, recoveryInfo); + currentInfo.getUrl(), psName, psArgs, nearLength, new ArrayList<>(recoveryInfo)); Toast.makeText(context, getString(R.string.download_has_started), Toast.LENGTH_SHORT).show(); diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java index 6b34c8e90..831a8cc4b 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java @@ -17,6 +17,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.content.IntentCompat; import com.grack.nanojson.JsonWriter; @@ -105,7 +106,7 @@ public class ErrorActivity extends AppCompatActivity { actionBar.setDisplayShowTitleEnabled(true); } - errorInfo = intent.getParcelableExtra(ERROR_INFO); + errorInfo = IntentCompat.getParcelableExtra(intent, ERROR_INFO, ErrorInfo.class); // important add guru meditation addGuruMeditation(); diff --git a/app/src/main/java/org/schabi/newpipe/ktx/Bundle.kt b/app/src/main/java/org/schabi/newpipe/ktx/Bundle.kt new file mode 100644 index 000000000..61721d546 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/ktx/Bundle.kt @@ -0,0 +1,9 @@ +package org.schabi.newpipe.ktx + +import android.os.Bundle +import android.os.Parcelable +import androidx.core.os.BundleCompat + +inline fun Bundle.parcelableArrayList(key: String?): ArrayList? { + return BundleCompat.getParcelableArrayList(this, key, T::class.java) +} diff --git a/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt b/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt index de640dbbb..a40bf35dc 100644 --- a/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt +++ b/app/src/main/java/org/schabi/newpipe/local/feed/notifications/NotificationWorker.kt @@ -137,7 +137,7 @@ class NotificationWorker( .enqueueUniquePeriodicWork( WORK_TAG, if (force) { - ExistingPeriodicWorkPolicy.REPLACE + ExistingPeriodicWorkPolicy.CANCEL_AND_REENQUEUE } else { ExistingPeriodicWorkPolicy.KEEP }, diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java index d56d16f3c..54809068a 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java @@ -25,6 +25,7 @@ import android.content.Intent; import android.net.Uri; import android.util.Log; +import androidx.core.content.IntentCompat; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.reactivestreams.Subscriber; @@ -65,7 +66,7 @@ public class SubscriptionsExportService extends BaseImportExportService { return START_NOT_STICKY; } - final Uri path = intent.getParcelableExtra(KEY_FILE_PATH); + final Uri path = IntentCompat.getParcelableExtra(intent, KEY_FILE_PATH, Uri.class); if (path == null) { stopAndReportError(new IllegalStateException( "Exporting to a file, but the path is null"), diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsImportService.java b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsImportService.java index d624e1038..442c7fddb 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsImportService.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsImportService.java @@ -30,6 +30,7 @@ import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.content.IntentCompat; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.reactivestreams.Subscriber; @@ -108,7 +109,7 @@ public class SubscriptionsImportService extends BaseImportExportService { if (currentMode == CHANNEL_URL_MODE) { channelUrl = intent.getStringExtra(KEY_VALUE); } else { - final Uri uri = intent.getParcelableExtra(KEY_VALUE); + final Uri uri = IntentCompat.getParcelableExtra(intent, KEY_VALUE, Uri.class); if (uri == null) { stopAndReportError(new IllegalStateException( "Importing from input stream, but file path is null"), diff --git a/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt b/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt index 8acd70413..ff0bb269d 100644 --- a/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt +++ b/app/src/main/java/org/schabi/newpipe/player/gesture/MainPlayerGestureListener.kt @@ -160,13 +160,12 @@ class MainPlayerGestureListener( } override fun onScroll( - initialEvent: MotionEvent, + initialEvent: MotionEvent?, movingEvent: MotionEvent, distanceX: Float, distanceY: Float ): Boolean { - - if (!playerUi.isFullscreen) { + if (initialEvent == null || !playerUi.isFullscreen) { return false } diff --git a/app/src/main/java/org/schabi/newpipe/player/gesture/PopupPlayerGestureListener.kt b/app/src/main/java/org/schabi/newpipe/player/gesture/PopupPlayerGestureListener.kt index 23edcaeb8..0b94bf364 100644 --- a/app/src/main/java/org/schabi/newpipe/player/gesture/PopupPlayerGestureListener.kt +++ b/app/src/main/java/org/schabi/newpipe/player/gesture/PopupPlayerGestureListener.kt @@ -167,7 +167,7 @@ class PopupPlayerGestureListener( } override fun onFling( - e1: MotionEvent, + e1: MotionEvent?, e2: MotionEvent, velocityX: Float, velocityY: Float @@ -218,11 +218,14 @@ class PopupPlayerGestureListener( } override fun onScroll( - initialEvent: MotionEvent, + initialEvent: MotionEvent?, movingEvent: MotionEvent, distanceX: Float, distanceY: Float ): Boolean { + if (initialEvent == null) { + return false + } if (isResizing) { return super.onScroll(initialEvent, movingEvent, distanceX, distanceY) diff --git a/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java b/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java index 05c2e3af6..3fa7c2623 100644 --- a/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java +++ b/app/src/main/java/org/schabi/newpipe/player/notification/NotificationUtil.java @@ -364,7 +364,7 @@ public final class NotificationUtil { final Bitmap thumbnail = player.getThumbnail(); if (thumbnail == null || !showThumbnail) { // since the builder is reused, make sure the thumbnail is unset if there is not one - builder.setLargeIcon(null); + builder.setLargeIcon((Bitmap) null); return; } diff --git a/app/src/main/java/org/schabi/newpipe/util/StateSaver.java b/app/src/main/java/org/schabi/newpipe/util/StateSaver.java index 91dc5f35b..61fdb602f 100644 --- a/app/src/main/java/org/schabi/newpipe/util/StateSaver.java +++ b/app/src/main/java/org/schabi/newpipe/util/StateSaver.java @@ -27,6 +27,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.os.BundleCompat; import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.MainActivity; @@ -82,7 +83,8 @@ public final class StateSaver { return null; } - final SavedState savedState = outState.getParcelable(KEY_SAVED_STATE); + final SavedState savedState = BundleCompat.getParcelable( + outState, KEY_SAVED_STATE, SavedState.class); if (savedState == null) { return null; } diff --git a/app/src/main/java/org/schabi/newpipe/views/player/CircleClipTapView.kt b/app/src/main/java/org/schabi/newpipe/views/player/CircleClipTapView.kt index e3d142916..8554e7194 100644 --- a/app/src/main/java/org/schabi/newpipe/views/player/CircleClipTapView.kt +++ b/app/src/main/java/org/schabi/newpipe/views/player/CircleClipTapView.kt @@ -80,10 +80,10 @@ class CircleClipTapView(context: Context?, attrs: AttributeSet) : View(context, updatePathShape() } - override fun onDraw(canvas: Canvas?) { + override fun onDraw(canvas: Canvas) { super.onDraw(canvas) - canvas?.clipPath(shapePath) - canvas?.drawPath(shapePath, backgroundPaint) + canvas.clipPath(shapePath) + canvas.drawPath(shapePath, backgroundPaint) } } diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java index 009a4f4be..42ff3ca8c 100755 --- a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java +++ b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java @@ -23,7 +23,6 @@ import android.os.Handler; import android.os.Handler.Callback; import android.os.IBinder; import android.os.Message; -import android.os.Parcelable; import android.util.Log; import android.widget.Toast; @@ -36,6 +35,7 @@ import androidx.core.app.NotificationCompat.Builder; import androidx.core.app.PendingIntentCompat; import androidx.core.app.ServiceCompat; import androidx.core.content.ContextCompat; +import androidx.core.content.IntentCompat; import androidx.preference.PreferenceManager; import org.schabi.newpipe.R; @@ -49,6 +49,7 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import us.shandian.giga.get.DownloadMission; import us.shandian.giga.get.MissionRecoveryInfo; @@ -359,29 +360,29 @@ public class DownloadManagerService extends Service { */ public static void startMission(Context context, String[] urls, StoredFileHelper storage, char kind, int threads, String source, String psName, - String[] psArgs, long nearLength, MissionRecoveryInfo[] recoveryInfo) { - Intent intent = new Intent(context, DownloadManagerService.class); - intent.setAction(Intent.ACTION_RUN); - intent.putExtra(EXTRA_URLS, urls); - intent.putExtra(EXTRA_KIND, kind); - intent.putExtra(EXTRA_THREADS, threads); - intent.putExtra(EXTRA_SOURCE, source); - intent.putExtra(EXTRA_POSTPROCESSING_NAME, psName); - intent.putExtra(EXTRA_POSTPROCESSING_ARGS, psArgs); - intent.putExtra(EXTRA_NEAR_LENGTH, nearLength); - intent.putExtra(EXTRA_RECOVERY_INFO, recoveryInfo); - - intent.putExtra(EXTRA_PARENT_PATH, storage.getParentUri()); - intent.putExtra(EXTRA_PATH, storage.getUri()); - intent.putExtra(EXTRA_STORAGE_TAG, storage.getTag()); + String[] psArgs, long nearLength, + ArrayList recoveryInfo) { + final Intent intent = new Intent(context, DownloadManagerService.class) + .setAction(Intent.ACTION_RUN) + .putExtra(EXTRA_URLS, urls) + .putExtra(EXTRA_KIND, kind) + .putExtra(EXTRA_THREADS, threads) + .putExtra(EXTRA_SOURCE, source) + .putExtra(EXTRA_POSTPROCESSING_NAME, psName) + .putExtra(EXTRA_POSTPROCESSING_ARGS, psArgs) + .putExtra(EXTRA_NEAR_LENGTH, nearLength) + .putExtra(EXTRA_RECOVERY_INFO, recoveryInfo) + .putExtra(EXTRA_PARENT_PATH, storage.getParentUri()) + .putExtra(EXTRA_PATH, storage.getUri()) + .putExtra(EXTRA_STORAGE_TAG, storage.getTag()); context.startService(intent); } private void startMission(Intent intent) { String[] urls = intent.getStringArrayExtra(EXTRA_URLS); - Uri path = intent.getParcelableExtra(EXTRA_PATH); - Uri parentPath = intent.getParcelableExtra(EXTRA_PARENT_PATH); + Uri path = IntentCompat.getParcelableExtra(intent, EXTRA_PATH, Uri.class); + Uri parentPath = IntentCompat.getParcelableExtra(intent, EXTRA_PARENT_PATH, Uri.class); int threads = intent.getIntExtra(EXTRA_THREADS, 1); char kind = intent.getCharExtra(EXTRA_KIND, '?'); String psName = intent.getStringExtra(EXTRA_POSTPROCESSING_NAME); @@ -389,7 +390,9 @@ public class DownloadManagerService extends Service { String source = intent.getStringExtra(EXTRA_SOURCE); long nearLength = intent.getLongExtra(EXTRA_NEAR_LENGTH, 0); String tag = intent.getStringExtra(EXTRA_STORAGE_TAG); - Parcelable[] parcelRecovery = intent.getParcelableArrayExtra(EXTRA_RECOVERY_INFO); + final var recovery = IntentCompat.getParcelableArrayListExtra(intent, EXTRA_RECOVERY_INFO, + MissionRecoveryInfo.class); + Objects.requireNonNull(recovery); StoredFileHelper storage; try { @@ -404,15 +407,11 @@ public class DownloadManagerService extends Service { else ps = Postprocessing.getAlgorithm(psName, psArgs); - MissionRecoveryInfo[] recovery = new MissionRecoveryInfo[parcelRecovery.length]; - for (int i = 0; i < parcelRecovery.length; i++) - recovery[i] = (MissionRecoveryInfo) parcelRecovery[i]; - final DownloadMission mission = new DownloadMission(urls, storage, kind, ps); mission.threadCount = threads; mission.source = source; mission.nearLength = nearLength; - mission.recoveryInfo = recovery; + mission.recoveryInfo = recovery.toArray(MissionRecoveryInfo[]::new); if (ps != null) ps.setTemporalDir(DownloadManager.pickAvailableTemporalDir(this));