diff --git a/app/src/main/java/com/foxx/androidcast/AppPreferences.java b/app/src/main/java/com/foxx/androidcast/AppPreferences.java index 3295935..d97a17f 100644 --- a/app/src/main/java/com/foxx/androidcast/AppPreferences.java +++ b/app/src/main/java/com/foxx/androidcast/AppPreferences.java @@ -18,6 +18,8 @@ public final class AppPreferences { private static final String KEY_THEME = "theme_mode"; private static final String KEY_LOCALE = "locale_mode"; private static final String KEY_PLAY_INCOMING_AUDIO = "play_incoming_audio"; + private static final String KEY_DEV_RECEIVER_DEBUG_OVERLAY = "dev_receiver_debug_overlay"; + private static final String KEY_DEV_GRAB_SESSION_STATS = "dev_grab_session_stats"; private static final String PREFIX_SENDER = "sender_"; private static final String PREFIX_RECEIVER = "receiver_"; @@ -92,6 +94,24 @@ public final class AppPreferences { prefs(context).edit().putBoolean(KEY_PLAY_INCOMING_AUDIO, play).apply(); } + /** Developer: metrics HTML overlay on receiver video (default on). */ + public static boolean isShowReceiverDebugOverlay(Context context) { + return prefs(context).getBoolean(KEY_DEV_RECEIVER_DEBUG_OVERLAY, true); + } + + public static void setShowReceiverDebugOverlay(Context context, boolean show) { + prefs(context).edit().putBoolean(KEY_DEV_RECEIVER_DEBUG_OVERLAY, show).apply(); + } + + /** Developer: write anonymous session_*.json files (default on). */ + public static boolean isGrabSessionStats(Context context) { + return prefs(context).getBoolean(KEY_DEV_GRAB_SESSION_STATS, true); + } + + public static void setGrabSessionStats(Context context, boolean grab) { + prefs(context).edit().putBoolean(KEY_DEV_GRAB_SESSION_STATS, grab).apply(); + } + public static CastSettings loadSenderDefaults(Context context) { CastSettings s = new CastSettings(); applyStoredCastSettings(context, PREFIX_SENDER, s); diff --git a/app/src/main/java/com/foxx/androidcast/CastConfig.java b/app/src/main/java/com/foxx/androidcast/CastConfig.java index 0bf801e..333b6eb 100644 --- a/app/src/main/java/com/foxx/androidcast/CastConfig.java +++ b/app/src/main/java/com/foxx/androidcast/CastConfig.java @@ -56,9 +56,6 @@ public final class CastConfig { /** Max UDP payload chunk (fits typical Wi‑Fi MTU with header). */ public static final int UDP_CHUNK_SIZE = 1200; - /** Show diagnostics overlay on receiver playback (debug). */ - public static final boolean SHOW_CAST_DIAGNOSTICS = true; - /** Max retained session stat JSON files (room for one new file on next session). */ public static final int SESSION_STATS_MAX_FILES = 20; diff --git a/app/src/main/java/com/foxx/androidcast/DeveloperSettingsActivity.java b/app/src/main/java/com/foxx/androidcast/DeveloperSettingsActivity.java index 799335f..6614eff 100644 --- a/app/src/main/java/com/foxx/androidcast/DeveloperSettingsActivity.java +++ b/app/src/main/java/com/foxx/androidcast/DeveloperSettingsActivity.java @@ -1,15 +1,34 @@ package com.foxx.androidcast; +import android.content.Context; import android.os.Bundle; +import android.widget.CheckBox; import androidx.appcompat.app.AppCompatActivity; /** Hidden developer settings (opened via version label easter egg). */ public class DeveloperSettingsActivity extends AppCompatActivity { + @Override + protected void attachBaseContext(Context newBase) { + super.attachBaseContext(CastLocaleHelper.attach(newBase)); + } + @Override protected void onCreate(Bundle savedInstanceState) { + CastThemeHelper.applyTheme(this); super.onCreate(savedInstanceState); setContentView(R.layout.activity_developer_settings); setTitle(R.string.developer_settings_title); + + CheckBox debugOverlay = findViewById(R.id.check_receiver_debug_overlay); + CheckBox sessionStats = findViewById(R.id.check_grab_session_stats); + + debugOverlay.setChecked(AppPreferences.isShowReceiverDebugOverlay(this)); + sessionStats.setChecked(AppPreferences.isGrabSessionStats(this)); + + debugOverlay.setOnCheckedChangeListener((buttonView, isChecked) -> + AppPreferences.setShowReceiverDebugOverlay(this, isChecked)); + sessionStats.setOnCheckedChangeListener((buttonView, isChecked) -> + AppPreferences.setGrabSessionStats(this, isChecked)); } } diff --git a/app/src/main/java/com/foxx/androidcast/MainActivity.java b/app/src/main/java/com/foxx/androidcast/MainActivity.java index 181a94d..d8bcec0 100644 --- a/app/src/main/java/com/foxx/androidcast/MainActivity.java +++ b/app/src/main/java/com/foxx/androidcast/MainActivity.java @@ -17,7 +17,9 @@ public class MainActivity extends DrawerHostActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - SessionStatsStore.pruneOnAppStart(this); + if (AppPreferences.isGrabSessionStats(this)) { + SessionStatsStore.pruneOnAppStart(this); + } com.foxx.androidcast.network.CastTransportFactory.init(this); PermissionHelper.request(this); diff --git a/app/src/main/java/com/foxx/androidcast/receiver/ReceiverCastService.java b/app/src/main/java/com/foxx/androidcast/receiver/ReceiverCastService.java index c0930eb..1a2f408 100644 --- a/app/src/main/java/com/foxx/androidcast/receiver/ReceiverCastService.java +++ b/app/src/main/java/com/foxx/androidcast/receiver/ReceiverCastService.java @@ -159,7 +159,9 @@ public class ReceiverCastService extends Service { public void onCreate() { super.onCreate(); CastNotifications.createChannels(this); - SessionStatsStore.pruneOnAppStart(this); + if (AppPreferences.isGrabSessionStats(this)) { + SessionStatsStore.pruneOnAppStart(this); + } videoDecodeThread = new HandlerThread("VideoDecode"); videoDecodeThread.start(); videoDecodeHandler = new Handler(videoDecodeThread.getLooper()); @@ -375,12 +377,14 @@ public class ReceiverCastService extends Service { private void onSenderConnected(String senderName, CastSettings remoteSettings, String videoMime) { phase = Phase.CONNECTED; castEnded = false; - if (sessionStatsRecorder == null) { - sessionStatsRecorder = new SessionStatsRecorder("receiver", settings.getTransport()); - sessionStatsRecorder.setClientCount(1); + if (AppPreferences.isGrabSessionStats(this)) { + if (sessionStatsRecorder == null) { + sessionStatsRecorder = new SessionStatsRecorder("receiver", settings.getTransport()); + sessionStatsRecorder.setClientCount(1); + } + sessionStatsRecorder.mergeSettings(remoteSettings); + sessionStatsRecorder.setCodecs(videoMime, "AAC"); } - sessionStatsRecorder.mergeSettings(remoteSettings); - sessionStatsRecorder.setCodecs(videoMime, "AAC"); negotiatedVideoMime = videoMime; remoteCastSettings = remoteSettings; streamIdle = false; diff --git a/app/src/main/java/com/foxx/androidcast/receiver/ReceiverPlaybackActivity.java b/app/src/main/java/com/foxx/androidcast/receiver/ReceiverPlaybackActivity.java index 0428efa..16942f6 100644 --- a/app/src/main/java/com/foxx/androidcast/receiver/ReceiverPlaybackActivity.java +++ b/app/src/main/java/com/foxx/androidcast/receiver/ReceiverPlaybackActivity.java @@ -23,7 +23,6 @@ import android.widget.ImageView; import android.widget.TextView; import com.foxx.androidcast.AppPreferences; -import com.foxx.androidcast.CastConfig; import com.foxx.androidcast.CastSettings; import com.foxx.androidcast.DrawerHostActivity; import com.foxx.androidcast.CastThemeHelper; @@ -296,7 +295,7 @@ public class ReceiverPlaybackActivity extends DrawerHostActivity { if (diagnosticsText == null) { return; } - boolean show = CastConfig.SHOW_CAST_DIAGNOSTICS && streamRendering; + boolean show = AppPreferences.isShowReceiverDebugOverlay(this) && streamRendering; diagnosticsText.setVisibility(show ? View.VISIBLE : View.GONE); if (show) { diagnosticsText.bringToFront(); @@ -304,7 +303,8 @@ public class ReceiverPlaybackActivity extends DrawerHostActivity { } private void refreshDiagnostics() { - if (diagnosticsText == null || !CastConfig.SHOW_CAST_DIAGNOSTICS || !bound || receiverService == null) { + if (diagnosticsText == null || !AppPreferences.isShowReceiverDebugOverlay(this) + || !bound || receiverService == null) { return; } if (!streamRendering) { diff --git a/app/src/main/java/com/foxx/androidcast/sender/ScreenCastService.java b/app/src/main/java/com/foxx/androidcast/sender/ScreenCastService.java index 2b972ec..05125da 100644 --- a/app/src/main/java/com/foxx/androidcast/sender/ScreenCastService.java +++ b/app/src/main/java/com/foxx/androidcast/sender/ScreenCastService.java @@ -153,7 +153,9 @@ public class ScreenCastService extends Service implements @Override public void onCreate() { super.onCreate(); - SessionStatsStore.pruneOnAppStart(this); + if (AppPreferences.isGrabSessionStats(this)) { + SessionStatsStore.pruneOnAppStart(this); + } CastNotifications.createChannels(this); com.foxx.androidcast.network.CastTransportFactory.init(this); projectionThread = new HandlerThread("CastProjection"); @@ -263,10 +265,12 @@ public class ScreenCastService extends Service implements CastActiveState.setSenderCasting(true); CastTrayNotifier.refresh(this); activeSettings = settings; - sessionStatsRecorder = new SessionStatsRecorder("sender", settings.getTransport()); - sessionStatsRecorder.mergeSettings(settings); - sessionStatsRecorder.setClientCount(peers.size()); - sessionStatsRecorder.setCodecs(settings.getNegotiatedVideoMime(), "AAC"); + if (AppPreferences.isGrabSessionStats(this)) { + sessionStatsRecorder = new SessionStatsRecorder("sender", settings.getTransport()); + sessionStatsRecorder.mergeSettings(settings); + sessionStatsRecorder.setClientCount(peers.size()); + sessionStatsRecorder.setCodecs(settings.getNegotiatedVideoMime(), "AAC"); + } final int projResultCode = resultCode; final Intent projData = data != null ? new Intent(data) : null; if (calibration) { diff --git a/app/src/main/java/com/foxx/androidcast/stats/SessionStatsRecorder.java b/app/src/main/java/com/foxx/androidcast/stats/SessionStatsRecorder.java index a9f2ac4..d67afac 100644 --- a/app/src/main/java/com/foxx/androidcast/stats/SessionStatsRecorder.java +++ b/app/src/main/java/com/foxx/androidcast/stats/SessionStatsRecorder.java @@ -2,6 +2,7 @@ package com.foxx.androidcast.stats; import android.content.Context; +import com.foxx.androidcast.AppPreferences; import com.foxx.androidcast.CastSettings; import com.foxx.androidcast.network.control.NetworkStatsSnapshot; import com.foxx.androidcast.network.transport.TransportLossStats; @@ -139,6 +140,9 @@ public final class SessionStatsRecorder { } public void finish(Context context) { + if (!AppPreferences.isGrabSessionStats(context)) { + return; + } long endedMs = System.currentTimeMillis(); try { JSONObject root = new JSONObject(); diff --git a/app/src/main/res/layout/activity_developer_settings.xml b/app/src/main/res/layout/activity_developer_settings.xml index 0c3ab54..293771c 100644 --- a/app/src/main/res/layout/activity_developer_settings.xml +++ b/app/src/main/res/layout/activity_developer_settings.xml @@ -1,22 +1,36 @@ - + android:fillViewport="true"> - + android:orientation="vertical" + android:padding="24dp"> - - + + + + + + + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 03649d5..a67242a 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -186,7 +186,8 @@ Лицензии Не могу найти факл лицензий Для разработчиков - Additional developer options will appear here. + Показывать отладочный оверлей на приёмнике + Сохранять анонимную статистику сессий Кодек для звука libvpx (VP8) libvpx (VP9) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c0130fa..1ca83d9 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -186,7 +186,8 @@ Licenses Could not load license text. Developer settings - Additional developer options will appear here. + Show debug overlay on receiver + Grab anonymous session stats Voice codec libvpx (VP8) libvpx (VP9) diff --git a/pull_stats.sh b/pull_stats.sh index 9c981ad..1ee3264 100755 --- a/pull_stats.sh +++ b/pull_stats.sh @@ -1,3 +1,21 @@ -#!/bin/sh -adb shell run-as com.foxx.androidcast ls files/session_stats/ -adb shell run-as com.foxx.androidcast cat files/session_stats/session_*.json +#!/bin/bash +DEVICES_LIST="$(adb devices -l)" +echo "${DEVICES_LIST}" + + +filter_out() { + local -n dev_string=${1} + [[ ${dev_string} =~ List* ]] && dev_string="" + return 0 +} + +echo "${DEVICES_LIST}" | while IFS= read -r DEV; do + SERIAL="$(echo "${DEV}" | awk '{print $1}')" + filter_out SERIAL + [ -z "${SERIAL}" ] && continue +# echo "Device: ${DEV}" +# echo "Serial: ${SERIAL}" + adb -s "${SERIAL}" shell run-as com.foxx.androidcast ls files/session_stats/ + adb -s "${SERIAL}" shell run-as com.foxx.androidcast cat files/session_stats/session_*.json +done +