Skip to content

Commit 5246db3

Browse files
authored
Merge pull request #217 from tobexyz/develop
5.0.1 to master
2 parents d82a51e + e35b41b commit 5246db3

29 files changed

Lines changed: 228 additions & 112 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
reports
12
.kiro
23
doxygen
34
.bundle

README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,15 @@ tobexyz
1515
alt="Get it on F-Droid"
1616
height="80">](https://f-droid.org/packages/de.yaacc/)
1717

18-
<img src="./docs/screenshots/4.4.x/browse_servers.png" alt= “” width="30%" height="30%"> <img src="./docs/screenshots/4.4.x/browse_image_folder.png" alt= “” width="30%" height="30%"> <img src="./docs/screenshots/4.4.x/browse_receiver.png" alt= “” width="30%" height="30%">
19-
<img src="./docs/screenshots/4.2.x/music_player.png" alt= “” width="30%" height="30%"> <img src="./docs/screenshots/4.4.x/playlist_fully_editable.png" alt= “” width="30%" height="30%"> <img src="./docs/screenshots/4.4.x/image_player_show_menu.png" alt= “” width="30%" height="30%">
18+
19+
![Downloads last month](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgithub.com%2Fkitswas%2Ffdroid-metrics-dashboard%2Fraw%2Frefs%2Fheads%2Fmain%2Fprocessed%2Fmonthly%2Fde.yaacc.json&query=%24.total_downloads&logo=fdroid&label=Downloads%20last%20month)
20+
21+
22+
![Downloads (all time)](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fgithub.com%2Fkitswas%2Ffdroid-metrics-dashboard%2Fraw%2Frefs%2Fheads%2Fmain%2Fprocessed%2Ftotal%2Fde.yaacc.json&query=%24.total_downloads&logo=fdroid&label=Downloads%20(all%20time))
23+
24+
25+
<img src="./docs/screenshots/5.0.x/browse_servers.png" alt= “” width="30%" height="30%"> <img src="./docs/screenshots/5.0.x/browse_image_folder.png" alt= “” width="30%" height="30%"> <img src="./docs/screenshots/5.0.x/browse_receiver.png" alt= “” width="30%" height="30%">
26+
<img src="./docs/screenshots/5.0.x/music_player.png" alt= “” width="30%" height="30%"> <img src="./docs/screenshots/5.0.x/playlist_fully_editable.png" alt= “” width="30%" height="30%"> <img src="./docs/screenshots/5.0.x/image_player_show_menu.png" alt= “” width="30%" height="30%">
2027

2128
## Description
2229

@@ -29,10 +36,15 @@ in order to play media from your device on any UPnP renderer in your network.
2936
* UPnP/DLNA Server - share files of your device in the network
3037
* UPnP/DLNA Client - receive media from other devices on your device
3138
* UPnP/DLNA Controller - control media renderer in the network
39+
* Live streaming - stream system audio and screen to network devices (Android 10+)
40+
* SAF support - browse and share files from external storage, USB drives, SD cards
41+
* Lock screen controls - hardware volume buttons and media controls
42+
* Receiver controls - play/pause/stop directly from receiver tab with status display
3243
* Control multiple media renderer
3344
* Allow download files to the device
3445
* Allow sharing of URLs and sending them to the current media renderers
3546
* Use your device as an proxy if your media renderer can't process https media URLs
47+
* Battery optimized with smart WiFi lock and foreground service management
3648

3749
## Configuration
3850

docs/Gemfile.lock

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,34 @@
11
GEM
22
remote: https://rubygems.org/
33
specs:
4-
activesupport (7.1.3.2)
4+
activesupport (7.2.3.1)
55
base64
6+
benchmark (>= 0.3)
67
bigdecimal
7-
concurrent-ruby (~> 1.0, >= 1.0.2)
8+
concurrent-ruby (~> 1.0, >= 1.3.1)
89
connection_pool (>= 2.2.5)
910
drb
1011
i18n (>= 1.6, < 2)
11-
minitest (>= 5.1)
12-
mutex_m
13-
tzinfo (~> 2.0)
14-
addressable (2.8.6)
15-
public_suffix (>= 2.0.2, < 6.0)
16-
base64 (0.2.0)
17-
bigdecimal (3.1.6)
12+
logger (>= 1.4.2)
13+
minitest (>= 5.1, < 6)
14+
securerandom (>= 0.3)
15+
tzinfo (~> 2.0, >= 2.0.5)
16+
addressable (2.9.0)
17+
public_suffix (>= 2.0.2, < 8.0)
18+
base64 (0.3.0)
19+
benchmark (0.5.0)
20+
bigdecimal (4.0.1)
1821
coffee-script (2.4.1)
1922
coffee-script-source
2023
execjs
2124
coffee-script-source (1.12.2)
2225
colorator (1.1.0)
2326
commonmarker (0.23.10)
24-
concurrent-ruby (1.2.3)
25-
connection_pool (2.4.1)
27+
concurrent-ruby (1.3.6)
28+
connection_pool (3.0.2)
2629
dnsruby (1.70.0)
2730
simpleidn (~> 0.2.1)
28-
drb (2.2.1)
31+
drb (2.2.3)
2932
em-websocket (0.5.3)
3033
eventmachine (>= 0.12.9)
3134
http_parser.rb (~> 0)
@@ -97,7 +100,7 @@ GEM
97100
activesupport (>= 2)
98101
nokogiri (>= 1.4)
99102
http_parser.rb (0.8.0)
100-
i18n (1.14.4)
103+
i18n (1.14.8)
101104
concurrent-ruby (~> 1.0)
102105
jekyll (3.9.5)
103106
addressable (~> 2.4)
@@ -207,7 +210,7 @@ GEM
207210
gemoji (>= 3, < 5)
208211
html-pipeline (~> 2.2)
209212
jekyll (>= 3.0, < 5.0)
210-
json (2.18.1)
213+
json (2.19.2)
211214
kramdown (2.4.0)
212215
rexml
213216
kramdown-parser-gfm (1.1.0)
@@ -222,8 +225,7 @@ GEM
222225
jekyll (>= 3.5, < 5.0)
223226
jekyll-feed (~> 0.9)
224227
jekyll-seo-tag (~> 2.1)
225-
minitest (5.22.2)
226-
mutex_m (0.2.0)
228+
minitest (5.27.0)
227229
net-http (0.9.1)
228230
uri (>= 0.11.1)
229231
nokogiri (1.19.1-x86_64-linux-gnu)
@@ -233,7 +235,7 @@ GEM
233235
sawyer (~> 0.9)
234236
pathutil (0.16.2)
235237
forwardable-extended (~> 2.6)
236-
public_suffix (5.0.4)
238+
public_suffix (5.1.1)
237239
racc (1.8.1)
238240
rb-fsevent (0.11.2)
239241
rb-inotify (0.10.1)
@@ -250,6 +252,7 @@ GEM
250252
sawyer (0.9.2)
251253
addressable (>= 2.3.5)
252254
faraday (>= 0.17.3, < 3)
255+
securerandom (0.4.1)
253256
simpleidn (0.2.1)
254257
unf (~> 0.1.4)
255258
terminal-table (1.8.0)
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Version 5.0.1
2+
- fixed crash on startup if no network device is found
3+
- fixed problems with device lookup

yaacc/src/main/AndroidManifest.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:tools="http://schemas.android.com/tools"
4-
android:versionCode="50000"
5-
android:versionName="5.0.0">
4+
android:versionCode="50001"
5+
android:versionName="5.0.1">
66

77
<uses-permission android:name="android.permission.INTERNET" />
88
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

yaacc/src/main/java/de/yaacc/browser/ServerListFragment.java

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import android.content.SharedPreferences;
2323
import android.graphics.drawable.Drawable;
2424
import android.os.Bundle;
25-
import de.yaacc.util.YaaccLogger;
2625
import android.view.LayoutInflater;
2726
import android.view.View;
2827
import android.view.ViewGroup;
@@ -53,6 +52,7 @@
5352
import de.yaacc.util.FormatHelper;
5453
import de.yaacc.util.ShutdownTimerListener;
5554
import de.yaacc.util.ThemeHelper;
55+
import de.yaacc.util.YaaccLogger;
5656

5757
/**
5858
* Activity for browsing devices and folders. Represents the entrypoint for the whole application.
@@ -81,7 +81,7 @@ private SharedPreferences getPreferences() {
8181
@Override
8282
public void onCreate(Bundle savedInstanceState) {
8383
super.onCreate(savedInstanceState);
84-
84+
8585
// Register callback for MediaProjection stop events
8686
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
8787
de.yaacc.upnp.server.media.MediaProjectionHelper.setStopCallback(() -> {
@@ -90,17 +90,17 @@ public void onCreate(Bundle savedInstanceState) {
9090
getActivity().runOnUiThread(() -> {
9191
android.content.SharedPreferences prefs = androidx.preference.PreferenceManager.getDefaultSharedPreferences(requireContext());
9292
prefs.edit()
93-
.putBoolean(getString(R.string.settings_local_server_serve_system_audio_chkbx), false)
94-
.putBoolean(getString(R.string.settings_local_server_serve_screen_cast_chkbx), false)
95-
.apply();
96-
93+
.putBoolean(getString(R.string.settings_local_server_serve_system_audio_chkbx), false)
94+
.putBoolean(getString(R.string.settings_local_server_serve_screen_cast_chkbx), false)
95+
.apply();
96+
9797
de.yaacc.browser.BrowseDeviceAdapter.setAudioStreaming(false);
9898
de.yaacc.browser.BrowseDeviceAdapter.setVideoStreaming(false);
99-
99+
100100
if (bDeviceAdapter != null) {
101101
bDeviceAdapter.notifyDataSetChanged();
102102
}
103-
103+
104104
YaaccLogger.i(getClass().getName(), "Streaming disabled - MediaProjection stopped");
105105
});
106106
}
@@ -192,6 +192,10 @@ public void receiverDeviceAdded(Device<?, ?, ?> device) {
192192
@Override
193193
public void onResume() {
194194
super.onResume();
195+
// Trigger UPnP discovery to find new devices
196+
if (upnpClient != null && upnpClient.isInitialized()) {
197+
upnpClient.searchDevices();
198+
}
195199
//refresh device list
196200
Thread thread = new Thread(this::populateDeviceList);
197201
thread.start();
@@ -345,21 +349,21 @@ public void setShutdownTimerRemainingTime(String s) {
345349
public void onTick(long millisUntilFinished) {
346350
setShutdownTimerRemainingTime(FormatHelper.parseMillisToTimeStringTo(millisUntilFinished));
347351
}
348-
352+
349353
@Override
350354
public void onActivityResult(int requestCode, int resultCode, android.content.Intent data) {
351355
super.onActivityResult(requestCode, resultCode, data);
352-
356+
353357
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q &&
354-
requestCode == de.yaacc.upnp.server.media.MediaProjectionHelper.REQUEST_CODE_MEDIA_PROJECTION) {
355-
358+
requestCode == de.yaacc.upnp.server.media.MediaProjectionHelper.REQUEST_CODE_MEDIA_PROJECTION) {
359+
356360
if (de.yaacc.upnp.server.media.MediaProjectionHelper.handlePermissionResult(requireContext(), resultCode, data)) {
357361
// Permission granted - enable only the button that requested it
358362
YaaccLogger.i(getClass().getName(), "MediaProjection permission granted");
359-
363+
360364
android.content.SharedPreferences prefs = androidx.preference.PreferenceManager.getDefaultSharedPreferences(requireContext());
361365
android.content.SharedPreferences.Editor editor = prefs.edit();
362-
366+
363367
// Enable only the button that requested permission
364368
if (de.yaacc.browser.BrowseDeviceAdapter.isPendingAudioRequest()) {
365369
editor.putBoolean(getString(R.string.settings_local_server_serve_system_audio_chkbx), true);
@@ -370,26 +374,26 @@ public void onActivityResult(int requestCode, int resultCode, android.content.In
370374
de.yaacc.browser.BrowseDeviceAdapter.setVideoStreaming(true);
371375
}
372376
editor.apply();
373-
377+
374378
// Clear pending flags
375379
de.yaacc.browser.BrowseDeviceAdapter.clearPendingRequests();
376-
380+
377381
// Refresh the adapter to update button states
378382
if (bDeviceAdapter != null) {
379383
bDeviceAdapter.notifyDataSetChanged();
380384
}
381385
} else {
382386
// Permission denied - disable both and clear pending
383387
YaaccLogger.w(getClass().getName(), "MediaProjection permission denied");
384-
388+
385389
de.yaacc.browser.BrowseDeviceAdapter.clearPendingRequests();
386-
390+
387391
android.content.SharedPreferences prefs = androidx.preference.PreferenceManager.getDefaultSharedPreferences(requireContext());
388392
prefs.edit()
389-
.putBoolean(getString(R.string.settings_local_server_serve_system_audio_chkbx), false)
390-
.putBoolean(getString(R.string.settings_local_server_serve_screen_cast_chkbx), false)
391-
.apply();
392-
393+
.putBoolean(getString(R.string.settings_local_server_serve_system_audio_chkbx), false)
394+
.putBoolean(getString(R.string.settings_local_server_serve_screen_cast_chkbx), false)
395+
.apply();
396+
393397
// Update adapter state
394398
if (bDeviceAdapter != null) {
395399
de.yaacc.browser.BrowseDeviceAdapter.setAudioStreaming(false);

yaacc/src/main/java/de/yaacc/upnp/protocol/UpnpProtocolHandler.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,8 @@ public Namespace getNamespace() {
162162
public ReceivingSync createReceivingSync(StreamRequestMessage message) throws ProtocolCreationException {
163163
YaaccLogger.v(getClass().getName(), "Creating protocol for incoming synchronous: " + message);
164164

165-
if (message.getOperation().getMethod().equals(UpnpRequest.Method.GET)) {
165+
if (message.getOperation().getMethod().equals(UpnpRequest.Method.GET) ||
166+
message.getOperation().getMethod().equals(UpnpRequest.Method.HEAD)) {
166167

167168
return createReceivingRetrieval(message);
168169

yaacc/src/main/java/de/yaacc/upnp/protocol/sync/ReceivingRetrieval.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,13 @@ protected StreamResponseMessage executeSync() throws IOException {
101101
}
102102
}
103103

104+
// HEAD requests don't need content, just return headers
105+
if (getInputMessage().getOperation().getMethod().equals(org.fourthline.cling.model.message.UpnpRequest.Method.HEAD)) {
106+
StreamResponseMessage response = new StreamResponseMessage(UpnpResponse.Status.OK);
107+
response.getHeaders().add(UpnpHeader.Type.SERVER, new ServerHeader());
108+
return response;
109+
}
110+
104111
return createResponse(requestedURI, foundResource);
105112
}
106113

yaacc/src/main/java/de/yaacc/upnp/registry/LocalItems.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import java.util.concurrent.Executors;
5353

5454
import de.yaacc.upnp.protocol.SendingAsync;
55+
import de.yaacc.upnp.protocol.UpnpProtocolHandler;
5556
import de.yaacc.util.YaaccLogger;
5657

5758
/**
@@ -321,12 +322,18 @@ public void run() {
321322
} catch (InterruptedException ex) {
322323
YaaccLogger.e(getClass().getName(), "Background execution interrupted: " + ex.getMessage());
323324
}
324-
registry.getUpnpProtocolHandler().createSendingNotificationAlive(localDevice).run();
325+
UpnpProtocolHandler handler = registry.getUpnpProtocolHandler();
326+
if (handler != null) {
327+
handler.createSendingNotificationAlive(localDevice).run();
328+
}
325329
}
326330
});
327331
}
328332

329333
protected void advertiseByebye(final LocalDevice localDevice, boolean asynchronous) {
334+
if (registry.getUpnpProtocolHandler() == null) {
335+
return;
336+
}
330337
final SendingAsync prot = registry.getUpnpProtocolHandler().createSendingNotificationByebye(localDevice);
331338
if (asynchronous) {
332339
registry.executeAsyncProtocol(prot);

0 commit comments

Comments
 (0)