mirror of
git://f0xx.org/android_cast
synced 2026-07-29 08:37:37 +03:00
snap
This commit is contained in:
@@ -18,6 +18,8 @@ public final class AppPreferences {
|
|||||||
private static final String KEY_THEME = "theme_mode";
|
private static final String KEY_THEME = "theme_mode";
|
||||||
private static final String KEY_LOCALE = "locale_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_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_SENDER = "sender_";
|
||||||
private static final String PREFIX_RECEIVER = "receiver_";
|
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();
|
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) {
|
public static CastSettings loadSenderDefaults(Context context) {
|
||||||
CastSettings s = new CastSettings();
|
CastSettings s = new CastSettings();
|
||||||
applyStoredCastSettings(context, PREFIX_SENDER, s);
|
applyStoredCastSettings(context, PREFIX_SENDER, s);
|
||||||
|
|||||||
@@ -56,9 +56,6 @@ public final class CastConfig {
|
|||||||
/** Max UDP payload chunk (fits typical Wi‑Fi MTU with header). */
|
/** Max UDP payload chunk (fits typical Wi‑Fi MTU with header). */
|
||||||
public static final int UDP_CHUNK_SIZE = 1200;
|
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). */
|
/** Max retained session stat JSON files (room for one new file on next session). */
|
||||||
public static final int SESSION_STATS_MAX_FILES = 20;
|
public static final int SESSION_STATS_MAX_FILES = 20;
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,34 @@
|
|||||||
package com.foxx.androidcast;
|
package com.foxx.androidcast;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
/** Hidden developer settings (opened via version label easter egg). */
|
/** Hidden developer settings (opened via version label easter egg). */
|
||||||
public class DeveloperSettingsActivity extends AppCompatActivity {
|
public class DeveloperSettingsActivity extends AppCompatActivity {
|
||||||
|
@Override
|
||||||
|
protected void attachBaseContext(Context newBase) {
|
||||||
|
super.attachBaseContext(CastLocaleHelper.attach(newBase));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
CastThemeHelper.applyTheme(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_developer_settings);
|
setContentView(R.layout.activity_developer_settings);
|
||||||
setTitle(R.string.developer_settings_title);
|
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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ public class MainActivity extends DrawerHostActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
if (AppPreferences.isGrabSessionStats(this)) {
|
||||||
SessionStatsStore.pruneOnAppStart(this);
|
SessionStatsStore.pruneOnAppStart(this);
|
||||||
|
}
|
||||||
com.foxx.androidcast.network.CastTransportFactory.init(this);
|
com.foxx.androidcast.network.CastTransportFactory.init(this);
|
||||||
PermissionHelper.request(this);
|
PermissionHelper.request(this);
|
||||||
|
|
||||||
|
|||||||
@@ -159,7 +159,9 @@ public class ReceiverCastService extends Service {
|
|||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
CastNotifications.createChannels(this);
|
CastNotifications.createChannels(this);
|
||||||
|
if (AppPreferences.isGrabSessionStats(this)) {
|
||||||
SessionStatsStore.pruneOnAppStart(this);
|
SessionStatsStore.pruneOnAppStart(this);
|
||||||
|
}
|
||||||
videoDecodeThread = new HandlerThread("VideoDecode");
|
videoDecodeThread = new HandlerThread("VideoDecode");
|
||||||
videoDecodeThread.start();
|
videoDecodeThread.start();
|
||||||
videoDecodeHandler = new Handler(videoDecodeThread.getLooper());
|
videoDecodeHandler = new Handler(videoDecodeThread.getLooper());
|
||||||
@@ -375,12 +377,14 @@ public class ReceiverCastService extends Service {
|
|||||||
private void onSenderConnected(String senderName, CastSettings remoteSettings, String videoMime) {
|
private void onSenderConnected(String senderName, CastSettings remoteSettings, String videoMime) {
|
||||||
phase = Phase.CONNECTED;
|
phase = Phase.CONNECTED;
|
||||||
castEnded = false;
|
castEnded = false;
|
||||||
|
if (AppPreferences.isGrabSessionStats(this)) {
|
||||||
if (sessionStatsRecorder == null) {
|
if (sessionStatsRecorder == null) {
|
||||||
sessionStatsRecorder = new SessionStatsRecorder("receiver", settings.getTransport());
|
sessionStatsRecorder = new SessionStatsRecorder("receiver", settings.getTransport());
|
||||||
sessionStatsRecorder.setClientCount(1);
|
sessionStatsRecorder.setClientCount(1);
|
||||||
}
|
}
|
||||||
sessionStatsRecorder.mergeSettings(remoteSettings);
|
sessionStatsRecorder.mergeSettings(remoteSettings);
|
||||||
sessionStatsRecorder.setCodecs(videoMime, "AAC");
|
sessionStatsRecorder.setCodecs(videoMime, "AAC");
|
||||||
|
}
|
||||||
negotiatedVideoMime = videoMime;
|
negotiatedVideoMime = videoMime;
|
||||||
remoteCastSettings = remoteSettings;
|
remoteCastSettings = remoteSettings;
|
||||||
streamIdle = false;
|
streamIdle = false;
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.foxx.androidcast.AppPreferences;
|
import com.foxx.androidcast.AppPreferences;
|
||||||
import com.foxx.androidcast.CastConfig;
|
|
||||||
import com.foxx.androidcast.CastSettings;
|
import com.foxx.androidcast.CastSettings;
|
||||||
import com.foxx.androidcast.DrawerHostActivity;
|
import com.foxx.androidcast.DrawerHostActivity;
|
||||||
import com.foxx.androidcast.CastThemeHelper;
|
import com.foxx.androidcast.CastThemeHelper;
|
||||||
@@ -296,7 +295,7 @@ public class ReceiverPlaybackActivity extends DrawerHostActivity {
|
|||||||
if (diagnosticsText == null) {
|
if (diagnosticsText == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
boolean show = CastConfig.SHOW_CAST_DIAGNOSTICS && streamRendering;
|
boolean show = AppPreferences.isShowReceiverDebugOverlay(this) && streamRendering;
|
||||||
diagnosticsText.setVisibility(show ? View.VISIBLE : View.GONE);
|
diagnosticsText.setVisibility(show ? View.VISIBLE : View.GONE);
|
||||||
if (show) {
|
if (show) {
|
||||||
diagnosticsText.bringToFront();
|
diagnosticsText.bringToFront();
|
||||||
@@ -304,7 +303,8 @@ public class ReceiverPlaybackActivity extends DrawerHostActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void refreshDiagnostics() {
|
private void refreshDiagnostics() {
|
||||||
if (diagnosticsText == null || !CastConfig.SHOW_CAST_DIAGNOSTICS || !bound || receiverService == null) {
|
if (diagnosticsText == null || !AppPreferences.isShowReceiverDebugOverlay(this)
|
||||||
|
|| !bound || receiverService == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!streamRendering) {
|
if (!streamRendering) {
|
||||||
|
|||||||
@@ -153,7 +153,9 @@ public class ScreenCastService extends Service implements
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
if (AppPreferences.isGrabSessionStats(this)) {
|
||||||
SessionStatsStore.pruneOnAppStart(this);
|
SessionStatsStore.pruneOnAppStart(this);
|
||||||
|
}
|
||||||
CastNotifications.createChannels(this);
|
CastNotifications.createChannels(this);
|
||||||
com.foxx.androidcast.network.CastTransportFactory.init(this);
|
com.foxx.androidcast.network.CastTransportFactory.init(this);
|
||||||
projectionThread = new HandlerThread("CastProjection");
|
projectionThread = new HandlerThread("CastProjection");
|
||||||
@@ -263,10 +265,12 @@ public class ScreenCastService extends Service implements
|
|||||||
CastActiveState.setSenderCasting(true);
|
CastActiveState.setSenderCasting(true);
|
||||||
CastTrayNotifier.refresh(this);
|
CastTrayNotifier.refresh(this);
|
||||||
activeSettings = settings;
|
activeSettings = settings;
|
||||||
|
if (AppPreferences.isGrabSessionStats(this)) {
|
||||||
sessionStatsRecorder = new SessionStatsRecorder("sender", settings.getTransport());
|
sessionStatsRecorder = new SessionStatsRecorder("sender", settings.getTransport());
|
||||||
sessionStatsRecorder.mergeSettings(settings);
|
sessionStatsRecorder.mergeSettings(settings);
|
||||||
sessionStatsRecorder.setClientCount(peers.size());
|
sessionStatsRecorder.setClientCount(peers.size());
|
||||||
sessionStatsRecorder.setCodecs(settings.getNegotiatedVideoMime(), "AAC");
|
sessionStatsRecorder.setCodecs(settings.getNegotiatedVideoMime(), "AAC");
|
||||||
|
}
|
||||||
final int projResultCode = resultCode;
|
final int projResultCode = resultCode;
|
||||||
final Intent projData = data != null ? new Intent(data) : null;
|
final Intent projData = data != null ? new Intent(data) : null;
|
||||||
if (calibration) {
|
if (calibration) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.foxx.androidcast.stats;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.foxx.androidcast.AppPreferences;
|
||||||
import com.foxx.androidcast.CastSettings;
|
import com.foxx.androidcast.CastSettings;
|
||||||
import com.foxx.androidcast.network.control.NetworkStatsSnapshot;
|
import com.foxx.androidcast.network.control.NetworkStatsSnapshot;
|
||||||
import com.foxx.androidcast.network.transport.TransportLossStats;
|
import com.foxx.androidcast.network.transport.TransportLossStats;
|
||||||
@@ -139,6 +140,9 @@ public final class SessionStatsRecorder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void finish(Context context) {
|
public void finish(Context context) {
|
||||||
|
if (!AppPreferences.isGrabSessionStats(context)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
long endedMs = System.currentTimeMillis();
|
long endedMs = System.currentTimeMillis();
|
||||||
try {
|
try {
|
||||||
JSONObject root = new JSONObject();
|
JSONObject root = new JSONObject();
|
||||||
|
|||||||
@@ -1,22 +1,36 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:gravity="center"
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="24dp">
|
android:padding="24dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/developer_settings_title"
|
android:text="@string/developer_settings_title"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp"
|
||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
|
|
||||||
<TextView
|
<CheckBox
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/check_receiver_debug_overlay"
|
||||||
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="24dp"
|
||||||
android:gravity="center"
|
android:checked="true"
|
||||||
android:text="@string/developer_settings_stub" />
|
android:text="@string/dev_show_receiver_debug_overlay" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/check_grab_session_stats"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:checked="true"
|
||||||
|
android:text="@string/dev_grab_session_stats" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|||||||
@@ -186,7 +186,8 @@
|
|||||||
<string name="licenses_title">Лицензии</string>
|
<string name="licenses_title">Лицензии</string>
|
||||||
<string name="licenses_load_error">Не могу найти факл лицензий</string>
|
<string name="licenses_load_error">Не могу найти факл лицензий</string>
|
||||||
<string name="developer_settings_title">Для разработчиков</string>
|
<string name="developer_settings_title">Для разработчиков</string>
|
||||||
<string name="developer_settings_stub">Additional developer options will appear here.</string>
|
<string name="dev_show_receiver_debug_overlay">Показывать отладочный оверлей на приёмнике</string>
|
||||||
|
<string name="dev_grab_session_stats">Сохранять анонимную статистику сессий</string>
|
||||||
<string name="label_audio_codec">Кодек для звука</string>
|
<string name="label_audio_codec">Кодек для звука</string>
|
||||||
<string name="codec_libvpx_vp8">libvpx (VP8)</string>
|
<string name="codec_libvpx_vp8">libvpx (VP8)</string>
|
||||||
<string name="codec_libvpx_vp9">libvpx (VP9)</string>
|
<string name="codec_libvpx_vp9">libvpx (VP9)</string>
|
||||||
|
|||||||
@@ -186,7 +186,8 @@
|
|||||||
<string name="licenses_title">Licenses</string>
|
<string name="licenses_title">Licenses</string>
|
||||||
<string name="licenses_load_error">Could not load license text.</string>
|
<string name="licenses_load_error">Could not load license text.</string>
|
||||||
<string name="developer_settings_title">Developer settings</string>
|
<string name="developer_settings_title">Developer settings</string>
|
||||||
<string name="developer_settings_stub">Additional developer options will appear here.</string>
|
<string name="dev_show_receiver_debug_overlay">Show debug overlay on receiver</string>
|
||||||
|
<string name="dev_grab_session_stats">Grab anonymous session stats</string>
|
||||||
<string name="label_audio_codec">Voice codec</string>
|
<string name="label_audio_codec">Voice codec</string>
|
||||||
<string name="codec_libvpx_vp8">libvpx (VP8)</string>
|
<string name="codec_libvpx_vp8">libvpx (VP8)</string>
|
||||||
<string name="codec_libvpx_vp9">libvpx (VP9)</string>
|
<string name="codec_libvpx_vp9">libvpx (VP9)</string>
|
||||||
|
|||||||
@@ -1,3 +1,21 @@
|
|||||||
#!/bin/sh
|
#!/bin/bash
|
||||||
adb shell run-as com.foxx.androidcast ls files/session_stats/
|
DEVICES_LIST="$(adb devices -l)"
|
||||||
adb shell run-as com.foxx.androidcast cat files/session_stats/session_*.json
|
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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user