mirror of
git://f0xx.org/android_cast
synced 2026-07-29 06:39:09 +03:00
AI: polish mobile parts
This commit is contained in:
@@ -42,11 +42,6 @@
|
||||
android:exported="false"
|
||||
android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize|keyboardHidden|density" />
|
||||
|
||||
<activity
|
||||
android:name=".receiver.ReceiverActivity"
|
||||
android:exported="false"
|
||||
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden" />
|
||||
|
||||
<activity
|
||||
android:name=".CastSettingsActivity"
|
||||
android:exported="false"
|
||||
|
||||
@@ -423,8 +423,12 @@ public final class AppPreferences {
|
||||
SharedPreferences p = prefs(context);
|
||||
String transport = p.getString(prefix + "transport", CastConfig.DEFAULT_TRANSPORT);
|
||||
s.setTransport(transport);
|
||||
s.setResolution(readEnum(p, prefix + "resolution", CastSettings.Resolution.values(),
|
||||
CastSettings.Resolution.ADAPTIVE));
|
||||
CastSettings.Resolution resolution = readEnum(p, prefix + "resolution",
|
||||
CastSettings.Resolution.values(), CastSettings.Resolution.ADAPTIVE);
|
||||
if (PREFIX_SENDER.equals(prefix)) {
|
||||
resolution = CastSettings.forPresetUi(resolution);
|
||||
}
|
||||
s.setResolution(resolution);
|
||||
s.setVideoCodec(readEnum(p, prefix + "video_codec", CastSettings.VideoCodec.values(),
|
||||
CastSettings.VideoCodec.AUTO));
|
||||
s.setBitrateMode(readEnum(p, prefix + "bitrate_mode", CastSettings.BitrateMode.values(),
|
||||
|
||||
@@ -117,6 +117,27 @@ public class CastSettings implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps legacy stored resolutions to the alpha sender presets
|
||||
* ({@link #FULL} / {@link #HD_720P} / {@link #SD_480P} / {@link #ADAPTIVE}).
|
||||
*/
|
||||
public static Resolution forPresetUi(Resolution stored) {
|
||||
if (stored == null) {
|
||||
return Resolution.ADAPTIVE;
|
||||
}
|
||||
switch (stored) {
|
||||
case FIXED_720P:
|
||||
return Resolution.HD_720P;
|
||||
case FIXED_1080P:
|
||||
return Resolution.FULL;
|
||||
case THREE_QUARTERS:
|
||||
case HALF:
|
||||
return Resolution.ADAPTIVE;
|
||||
default:
|
||||
return stored;
|
||||
}
|
||||
}
|
||||
|
||||
private String transport = CastConfig.DEFAULT_TRANSPORT;
|
||||
private Quality quality = Quality.MEDIUM;
|
||||
private Resolution resolution = Resolution.ADAPTIVE;
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
package com.foxx.androidcast.receiver;
|
||||
|
||||
/*********************************************************************
|
||||
* ReceiverActivity.java
|
||||
* Created at: Fri 15 May 2026 16:49:02 +0200
|
||||
* Updated at: Wed 20 May 2026 15:17:13 +0200 by Anton Afanasyeu <a.afanasieff@gmail.com>
|
||||
* Commit: 5d8e82d2e60a21fff3138d2a394ee4e8b4c6dcb8
|
||||
* class ReceiverActivity
|
||||
* Contributors:
|
||||
* - Anton Afanasyeu <a.afanasieff@gmail.com> (6 commits, 163 lines)
|
||||
* - Cursor Agent (project assistant)
|
||||
* Digest: SHA256 5ca140ebc07f2ed3353cce1db093f850230b3ed1657466551f96c7c1b8349f88
|
||||
**********************************************************************/
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.ServiceConnection;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import com.foxx.androidcast.AppPreferences;
|
||||
import com.foxx.androidcast.CastActivityTracker;
|
||||
import com.foxx.androidcast.CastSettings;
|
||||
import com.foxx.androidcast.ICastReceiverService;
|
||||
import com.foxx.androidcast.ICastStatusCallback;
|
||||
import com.foxx.androidcast.PermissionHelper;
|
||||
import com.foxx.androidcast.R;
|
||||
|
||||
/** Receiver setup — options live in {@link com.foxx.androidcast.CastSettingsActivity}. */
|
||||
public class ReceiverActivity extends AppCompatActivity {
|
||||
private final CastSettings castSettings = new CastSettings();
|
||||
|
||||
private TextView statusText;
|
||||
private ICastReceiverService receiverService;
|
||||
private boolean bound;
|
||||
|
||||
private final ICastStatusCallback.Stub statusCallback = new ICastStatusCallback.Stub() {
|
||||
@Override
|
||||
public void onStatus(String status) {
|
||||
runOnUiThread(() -> statusText.setText(status));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticated(String senderName) {
|
||||
runOnUiThread(() -> statusText.setText(getString(R.string.casting_from, senderName)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStreamStarted(int width, int height) {
|
||||
runOnUiThread(() -> statusText.setText(getString(R.string.playback_opened, width, height)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVideoRendering() {
|
||||
runOnUiThread(() -> statusText.setText(R.string.playback_rendering));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStreamIdle() {
|
||||
runOnUiThread(() -> statusText.setText(R.string.playback_awaiting_stream));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected() {
|
||||
runOnUiThread(() -> statusText.setText(R.string.waiting_sender));
|
||||
}
|
||||
};
|
||||
|
||||
private final ServiceConnection connection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
receiverService = ICastReceiverService.Stub.asInterface(service);
|
||||
bound = true;
|
||||
try {
|
||||
receiverService.registerCallback(statusCallback);
|
||||
statusText.setText(receiverService.getStatus());
|
||||
} catch (RemoteException e) {
|
||||
statusText.setText(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
receiverService = null;
|
||||
bound = false;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_receiver);
|
||||
PermissionHelper.request(this);
|
||||
castSettings.copyFrom(AppPreferences.loadReceiverDefaults(this));
|
||||
|
||||
statusText = findViewById(R.id.text_status);
|
||||
findViewById(R.id.btn_start_receiver).setOnClickListener(v -> startReceiverService());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
CastActivityTracker.onResume(this);
|
||||
PermissionHelper.remindIfMissing(this, AppPreferences.isPlayIncomingAudio(this));
|
||||
updateKeepScreenOn();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
bindService(new Intent(this, ReceiverCastService.class), connection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
if (bound && receiverService != null) {
|
||||
try {
|
||||
receiverService.unregisterCallback(statusCallback);
|
||||
} catch (RemoteException ignored) {
|
||||
}
|
||||
unbindService(connection);
|
||||
bound = false;
|
||||
receiverService = null;
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
private void updateKeepScreenOn() {
|
||||
if (bound && receiverService != null) {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
} else {
|
||||
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
}
|
||||
}
|
||||
|
||||
private void startReceiverService() {
|
||||
String pin = AppPreferences.getPin(this);
|
||||
boolean allowAudio = AppPreferences.isPlayIncomingAudio(this);
|
||||
ReceiverPrefs.setAllowAudio(this, allowAudio);
|
||||
|
||||
Intent intent = new Intent(this, ReceiverCastService.class);
|
||||
intent.setAction(ReceiverCastService.ACTION_START);
|
||||
intent.putExtra(ReceiverCastService.EXTRA_PIN, pin);
|
||||
intent.putExtra(ReceiverCastService.EXTRA_ALLOW_AUDIO, allowAudio);
|
||||
intent.putExtra(CastSettings.EXTRA, castSettings);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
startForegroundService(intent);
|
||||
} else {
|
||||
startService(intent);
|
||||
}
|
||||
statusText.setText(R.string.receiver_starting);
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
}
|
||||
}
|
||||
@@ -231,7 +231,7 @@ public class ScreenCastService extends Service implements
|
||||
cameraMode = settings.isCameraCapture();
|
||||
calibrationMode = settings.getCaptureMode() == CastSettings.CaptureMode.CALIBRATION_TEST;
|
||||
if (cameraMode && !com.foxx.androidcast.PlatformCastSupport.isCameraCaptureModeSupported()) {
|
||||
failAndStop(getString(R.string.capture_camera_not_implemented));
|
||||
failAndStop(getString(R.string.capture_camera_requires_api29));
|
||||
return;
|
||||
}
|
||||
int castPort = com.foxx.androidcast.CastConfig.portForTransport(settings.getTransport());
|
||||
|
||||
@@ -462,7 +462,7 @@ public class SenderActivity extends DrawerHostActivity {
|
||||
if (grantResults.length > 0 && grantResults[0] == android.content.pm.PackageManager.PERMISSION_GRANTED) {
|
||||
launchCastService(null, Activity.RESULT_OK);
|
||||
} else {
|
||||
Toast.makeText(this, R.string.capture_camera_not_implemented, Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(this, R.string.capture_camera_permission_denied, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ public final class SenderCapturePreview {
|
||||
Context ctx = textureView.getContext();
|
||||
if (ContextCompat.checkSelfPermission(ctx, Manifest.permission.CAMERA)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
showLabel(R.string.capture_camera_not_implemented);
|
||||
showLabel(R.string.capture_camera_permission_denied);
|
||||
return;
|
||||
}
|
||||
labelView.setVisibility(android.view.View.GONE);
|
||||
@@ -207,7 +207,7 @@ public final class SenderCapturePreview {
|
||||
CameraManager mgr = ctx.getSystemService(CameraManager.class);
|
||||
String id = chooseCamera(mgr, useFront);
|
||||
if (id == null) {
|
||||
showLabel(R.string.capture_camera_not_implemented);
|
||||
showLabel(R.string.capture_camera_open_failed);
|
||||
return;
|
||||
}
|
||||
surface.setDefaultBufferSize(640, 480);
|
||||
@@ -256,7 +256,7 @@ public final class SenderCapturePreview {
|
||||
}, handler);
|
||||
} catch (CameraAccessException | SecurityException e) {
|
||||
Log.w(TAG, "Open camera failed", e);
|
||||
showLabel(R.string.capture_camera_not_implemented);
|
||||
showLabel(R.string.capture_camera_open_failed);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.widget.Spinner;
|
||||
|
||||
import com.foxx.androidcast.BuildConfig;
|
||||
import com.foxx.androidcast.AppPreferences;
|
||||
import com.foxx.androidcast.CastSettings;
|
||||
import com.foxx.androidcast.CastSettingsBinder;
|
||||
@@ -16,6 +17,9 @@ public final class SenderResolutionUi {
|
||||
private SenderResolutionUi() {}
|
||||
|
||||
public static SenderResolutionUiMode mode(Context context) {
|
||||
if (!BuildConfig.DEBUG) {
|
||||
return SenderResolutionUiMode.SEPARATED;
|
||||
}
|
||||
return AppPreferences.getDevSenderResolutionUiMode(context);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="24dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/receiver_title"
|
||||
android:textSize="20sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_status"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/waiting_sender" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_start_receiver"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:text="@string/start_receiver" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/receiver_use_settings_hint"
|
||||
android:textSize="13sp" />
|
||||
</LinearLayout>
|
||||
@@ -33,7 +33,9 @@
|
||||
<string name="capture_calibration_test">Тест сигнала</string>
|
||||
<string name="capture_camera">Камера (лицевая)</string>
|
||||
<string name="capture_camera_unavailable">Источник для камеры (Android 10+)</string>
|
||||
<string name="capture_camera_not_implemented">Захват с камеры в стадии разработки. Выберите другой метод.</string>
|
||||
<string name="capture_camera_requires_api29">Захват с камеры доступен с Android 10. Выберите экран или калибровку.</string>
|
||||
<string name="capture_camera_permission_denied">Нет доступа к камере. Разрешите камеру или выберите другой режим.</string>
|
||||
<string name="capture_camera_open_failed">Не удалось открыть камеру. Выберите другой режим захвата.</string>
|
||||
<string name="casting_calibration">Передача калибрации %1$dx%2$d</string>
|
||||
<string name="casting_camera">Трансляция с камеры %1$dx%2$d</string>
|
||||
<string name="quality_low">Низкий (~1.5 Mbps, 24 fps)</string>
|
||||
|
||||
@@ -33,7 +33,9 @@
|
||||
<string name="capture_calibration_test">Calibration test pattern</string>
|
||||
<string name="capture_camera">Camera (rear Camera2)</string>
|
||||
<string name="capture_camera_unavailable">Camera source (requires Android 10+)</string>
|
||||
<string name="capture_camera_not_implemented">Camera capture is not implemented yet. Use screen or calibration test.</string>
|
||||
<string name="capture_camera_requires_api29">Camera capture requires Android 10 or newer. Use screen or calibration test.</string>
|
||||
<string name="capture_camera_permission_denied">Camera permission denied. Allow camera access or choose another capture mode.</string>
|
||||
<string name="capture_camera_open_failed">Could not open the camera. Try another capture mode.</string>
|
||||
<string name="casting_calibration">Calibration cast %1$dx%2$d</string>
|
||||
<string name="casting_camera">Camera cast %1$dx%2$d</string>
|
||||
<string name="quality_low">Low (~1.5 Mbps, 24 fps)</string>
|
||||
|
||||
@@ -30,6 +30,18 @@ public class CastResolutionTest {
|
||||
assertTrue(size.width > size.height);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forPresetUiMapsLegacyResolutions() {
|
||||
assertEquals(CastSettings.Resolution.HD_720P,
|
||||
CastSettings.forPresetUi(CastSettings.Resolution.FIXED_720P));
|
||||
assertEquals(CastSettings.Resolution.FULL,
|
||||
CastSettings.forPresetUi(CastSettings.Resolution.FIXED_1080P));
|
||||
assertEquals(CastSettings.Resolution.ADAPTIVE,
|
||||
CastSettings.forPresetUi(CastSettings.Resolution.HALF));
|
||||
assertEquals(CastSettings.Resolution.SD_480P,
|
||||
CastSettings.forPresetUi(CastSettings.Resolution.SD_480P));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sd480pCapsLongEdge() {
|
||||
CastSettings settings = new CastSettings();
|
||||
|
||||
Reference in New Issue
Block a user