mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-08-22 01:58:16 +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:
commit
be662a9f1a
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -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:
|
||||||
|
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
@ -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.
|
||||||
|
@ -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,9 +137,11 @@ class ErrorUtil {
|
|||||||
NotificationManagerCompat.from(context)
|
NotificationManagerCompat.from(context)
|
||||||
.notify(ERROR_REPORT_NOTIFICATION_ID, notificationBuilder.build())
|
.notify(ERROR_REPORT_NOTIFICATION_ID, notificationBuilder.build())
|
||||||
|
|
||||||
// since the notification is silent, also show a toast, otherwise the user is confused
|
ContextCompat.getMainExecutor(context).execute {
|
||||||
Toast.makeText(context, R.string.error_report_notification_toast, Toast.LENGTH_SHORT)
|
// since the notification is silent, also show a toast, otherwise the user is confused
|
||||||
.show()
|
Toast.makeText(context, R.string.error_report_notification_toast, Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getErrorActivityIntent(context: Context, errorInfo: ErrorInfo): Intent {
|
private fun getErrorActivityIntent(context: Context, errorInfo: ErrorInfo): Intent {
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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() + ", "
|
||||||
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
// /////////////////////////////////////////////////////////////////////////
|
// /////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -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() {
|
||||||
|
@ -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,16 +185,15 @@ 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)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the Android platform signing key signature. This key is never null.
|
* Finds the Android platform signing key signature. This key is never null.
|
||||||
|
@ -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;
|
||||||
|
27
app/src/main/res/values-v35/styles.xml
Normal file
27
app/src/main/res/values-v35/styles.xml
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user