2
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-08-22 10:09:39 +00:00

Merge branch 'dev' into Merge-dev-to-refactor

# Conflicts:
#	app/build.gradle
#	app/src/main/AndroidManifest.xml
#	app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java
#	app/src/main/java/org/schabi/newpipe/player/mediabrowser/PackageValidator.kt
This commit is contained in:
Isira Seneviratne 2025-07-24 19:27:01 +05:30
commit be662a9f1a
13 changed files with 69 additions and 25 deletions

View File

@ -72,8 +72,8 @@ jobs:
- api-level: 21 - api-level: 21
target: default target: default
arch: x86 arch: x86
- api-level: 33 - api-level: 35
target: google_apis # emulator API 33 only exists with Google APIs target: default
arch: x86_64 arch: x86_64
permissions: permissions:

View File

@ -17,14 +17,14 @@ plugins {
} }
android { android {
compileSdk 35 compileSdk 36
namespace 'org.schabi.newpipe' namespace 'org.schabi.newpipe'
defaultConfig { defaultConfig {
applicationId "org.schabi.newpipe" applicationId "org.schabi.newpipe"
resValue "string", "app_name", "NewPipe" resValue "string", "app_name", "NewPipe"
minSdk 21 minSdk 21
targetSdk 33 targetSdk 35
if (System.properties.containsKey('versionCodeOverride')) { if (System.properties.containsKey('versionCodeOverride')) {
versionCode System.getProperty('versionCodeOverride') as Integer versionCode System.getProperty('versionCodeOverride') as Integer
} else { } else {

View File

@ -10,6 +10,7 @@
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/> <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<!-- We need to be able to open links in the browser on API 30+ --> <!-- We need to be able to open links in the browser on API 30+ -->
@ -104,7 +105,10 @@
android:name="androidx.work.impl.foreground.SystemForegroundService" android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync" android:foregroundServiceType="dataSync"
tools:node="merge" /> tools:node="merge" />
<service android:name=".local.feed.service.FeedLoadService" />
<service
android:name=".local.feed.service.FeedLoadService"
android:foregroundServiceType="dataSync" />
<activity <activity
android:name=".PanicResponderActivity" android:name=".PanicResponderActivity"
@ -136,7 +140,9 @@
android:label="@string/app_name" android:label="@string/app_name"
android:launchMode="singleTask" /> android:launchMode="singleTask" />
<service android:name="us.shandian.giga.service.DownloadManagerService" /> <service
android:name="us.shandian.giga.service.DownloadManagerService"
android:foregroundServiceType="dataSync" />
<activity <activity
android:name=".util.FilePickerActivityHelper" android:name=".util.FilePickerActivityHelper"

View File

@ -47,6 +47,7 @@ import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.ActionBarDrawerToggle; import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.view.GravityCompat; import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout; import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
@ -868,7 +869,8 @@ public class MainActivity extends AppCompatActivity {
}; };
final IntentFilter intentFilter = new IntentFilter(); final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(VideoDetailFragment.ACTION_PLAYER_STARTED); intentFilter.addAction(VideoDetailFragment.ACTION_PLAYER_STARTED);
registerReceiver(broadcastReceiver, intentFilter); ContextCompat.registerReceiver(this, broadcastReceiver, intentFilter,
ContextCompat.RECEIVER_EXPORTED);
// If the PlayerHolder is not bound yet, but the service is running, try to bind to it. // If the PlayerHolder is not bound yet, but the service is running, try to bind to it.
// Once the connection is established, the ACTION_PLAYER_STARTED will be sent. // Once the connection is established, the ACTION_PLAYER_STARTED will be sent.

View File

@ -10,6 +10,7 @@ import android.widget.Toast
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.app.PendingIntentCompat import androidx.core.app.PendingIntentCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
@ -136,10 +137,12 @@ class ErrorUtil {
NotificationManagerCompat.from(context) NotificationManagerCompat.from(context)
.notify(ERROR_REPORT_NOTIFICATION_ID, notificationBuilder.build()) .notify(ERROR_REPORT_NOTIFICATION_ID, notificationBuilder.build())
ContextCompat.getMainExecutor(context).execute {
// since the notification is silent, also show a toast, otherwise the user is confused // since the notification is silent, also show a toast, otherwise the user is confused
Toast.makeText(context, R.string.error_report_notification_toast, Toast.LENGTH_SHORT) Toast.makeText(context, R.string.error_report_notification_toast, Toast.LENGTH_SHORT)
.show() .show()
} }
}
private fun getErrorActivityIntent(context: Context, errorInfo: ErrorInfo): Intent { private fun getErrorActivityIntent(context: Context, errorInfo: ErrorInfo): Intent {
val intent = Intent(context, ErrorActivity::class.java) val intent = Intent(context, ErrorActivity::class.java)

View File

@ -1302,7 +1302,7 @@ class VideoDetailFragment :
intentFilter.addAction(ACTION_SHOW_MAIN_PLAYER) intentFilter.addAction(ACTION_SHOW_MAIN_PLAYER)
intentFilter.addAction(ACTION_HIDE_MAIN_PLAYER) intentFilter.addAction(ACTION_HIDE_MAIN_PLAYER)
intentFilter.addAction(ACTION_PLAYER_STARTED) intentFilter.addAction(ACTION_PLAYER_STARTED)
activity.registerReceiver(broadcastReceiver, intentFilter) ContextCompat.registerReceiver(activity, broadcastReceiver, intentFilter, ContextCompat.RECEIVER_EXPORTED)
} }
/*////////////////////////////////////////////////////////////////////////// /*//////////////////////////////////////////////////////////////////////////

View File

@ -8,6 +8,7 @@ import android.util.Log;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.evernote.android.state.State; import com.evernote.android.state.State;
@ -42,6 +43,7 @@ public abstract class BaseListInfoFragment<I extends InfoItem, L extends ListInf
private final UserAction errorUserAction; private final UserAction errorUserAction;
protected L currentInfo; protected L currentInfo;
@Nullable
protected Page currentNextPage; protected Page currentNextPage;
protected Disposable currentWorker; protected Disposable currentWorker;

View File

@ -146,6 +146,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
private final SparseArrayCompat<String> menuItemToFilterName = new SparseArrayCompat<>(); private final SparseArrayCompat<String> menuItemToFilterName = new SparseArrayCompat<>();
private StreamingService service; private StreamingService service;
@Nullable
private Page nextPage; private Page nextPage;
private boolean showLocalSuggestions = true; private boolean showLocalSuggestions = true;
private boolean showRemoteSuggestions = true; private boolean showRemoteSuggestions = true;
@ -1096,7 +1097,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
infoListAdapter.addInfoItemList(result.getItems()); infoListAdapter.addInfoItemList(result.getItems());
nextPage = result.getNextPage(); nextPage = result.getNextPage();
if (!result.getErrors().isEmpty()) { if (!result.getErrors().isEmpty() && nextPage != null) {
showSnackBarError(new ErrorInfo(result.getErrors(), UserAction.SEARCHED, showSnackBarError(new ErrorInfo(result.getErrors(), UserAction.SEARCHED,
"\"" + searchString + "\" → pageUrl: " + nextPage.getUrl() + ", " "\"" + searchString + "\" → pageUrl: " + nextPage.getUrl() + ", "
+ "pageIds: " + nextPage.getIds() + ", " + "pageIds: " + nextPage.getIds() + ", "

View File

@ -31,6 +31,7 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.app.PendingIntentCompat import androidx.core.app.PendingIntentCompat
import androidx.core.app.ServiceCompat import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.disposables.Disposable import io.reactivex.rxjava3.disposables.Disposable
@ -200,7 +201,7 @@ class FeedLoadService : Service() {
} }
} }
} }
registerReceiver(broadcastReceiver, IntentFilter(ACTION_CANCEL)) ContextCompat.registerReceiver(this, broadcastReceiver, IntentFilter(ACTION_CANCEL), ContextCompat.RECEIVER_NOT_EXPORTED)
} }
// ///////////////////////////////////////////////////////////////////////// // /////////////////////////////////////////////////////////////////////////

View File

@ -60,6 +60,7 @@ import android.view.LayoutInflater;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.math.MathUtils; import androidx.core.math.MathUtils;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
@ -767,7 +768,8 @@ public final class Player implements PlaybackListener, Listener {
private void registerBroadcastReceiver() { private void registerBroadcastReceiver() {
// Try to unregister current first // Try to unregister current first
unregisterBroadcastReceiver(); unregisterBroadcastReceiver();
context.registerReceiver(broadcastReceiver, intentFilter); ContextCompat.registerReceiver(context, broadcastReceiver, intentFilter,
ContextCompat.RECEIVER_EXPORTED);
} }
private void unregisterBroadcastReceiver() { private void unregisterBroadcastReceiver() {

View File

@ -146,19 +146,18 @@ internal class PackageValidator(context: Context) {
*/ */
private fun buildCallerInfo(callingPackage: String): CallerPackageInfo? { private fun buildCallerInfo(callingPackage: String): CallerPackageInfo? {
val packageInfo = getPackageInfo(callingPackage) ?: return null val packageInfo = getPackageInfo(callingPackage) ?: return null
val applicationInfo = packageInfo.applicationInfo ?: return null
val appName = applicationInfo.loadLabel(packageManager).toString() val appName = packageInfo.applicationInfo?.loadLabel(packageManager).toString()
val uid = applicationInfo.uid val uid = packageInfo.applicationInfo?.uid ?: -1
val signature = getSignature(packageInfo) val signature = getSignature(packageInfo)
val requestedPermissions = packageInfo.requestedPermissions?.asSequence().orEmpty() val requestedPermissions = packageInfo.requestedPermissions?.asSequence().orEmpty()
val permissionFlags = packageInfo.requestedPermissionsFlags?.asSequence().orEmpty() val permissionFlags = packageInfo.requestedPermissionsFlags?.asSequence().orEmpty()
val activePermissions = (requestedPermissions zip permissionFlags) val activePermissions = (requestedPermissions zip permissionFlags)
.filter { (_, flag) -> flag and REQUESTED_PERMISSION_GRANTED != 0 } .filter { (permission, flag) -> flag and REQUESTED_PERMISSION_GRANTED != 0 }
.mapTo(mutableSetOf()) { (permission, _) -> permission } .mapTo(mutableSetOf()) { (permission, flag) -> permission }
return CallerPackageInfo(appName, callingPackage, uid, signature, activePermissions) return CallerPackageInfo(appName, callingPackage, uid, signature, activePermissions.toSet())
} }
/** /**
@ -186,15 +185,14 @@ internal class PackageValidator(context: Context) {
* returns `null` as the signature. * returns `null` as the signature.
*/ */
@Suppress("deprecation") @Suppress("deprecation")
private fun getSignature(packageInfo: PackageInfo): String? { private fun getSignature(packageInfo: PackageInfo): String? =
val signatures = packageInfo.signatures if (packageInfo.signatures == null || packageInfo.signatures!!.size != 1) {
return if (signatures == null || signatures.size != 1) {
// Security best practices dictate that an app should be signed with exactly one (1) // Security best practices dictate that an app should be signed with exactly one (1)
// signature. Because of this, if there are multiple signatures, reject it. // signature. Because of this, if there are multiple signatures, reject it.
null null
} else { } else {
getSignatureSha256(signatures[0].toByteArray()) val certificate = packageInfo.signatures!![0].toByteArray()
} getSignatureSha256(certificate)
} }
/** /**

View File

@ -3,6 +3,7 @@ package org.schabi.newpipe.player.playqueue;
import android.util.Log; import android.util.Log;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.InfoItem;
import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.ListExtractor;
@ -23,6 +24,7 @@ abstract class AbstractInfoPlayQueue<T extends ListInfo<? extends InfoItem>>
final int serviceId; final int serviceId;
final String baseUrl; final String baseUrl;
@Nullable
Page nextPage; Page nextPage;
private transient Disposable fetchReactor; private transient Disposable fetchReactor;

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Base Theme -->
<style name="Base.V35" parent="Base.V29">
<item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
</style>
<style name="Base" parent="Base.V35"/>
<!-- Light Theme -->
<style name="Base.V35.LightTheme" parent="Base.V29.LightTheme">
</style>
<style name="Base.LightTheme" parent="Base.V35.LightTheme" />
<!-- Dark Theme -->
<style name="Base.V35.DarkTheme" parent="Base.V29.DarkTheme">
</style>
<style name="Base.DarkTheme" parent="Base.V35.DarkTheme" />
<!-- Black Theme -->
<style name="Base.V35.BlackTheme" parent="Base.V29.BlackTheme">
</style>
<style name="Base.BlackTheme" parent="Base.V35.BlackTheme" />
</resources>