package invalid.lena.scrcpy; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.content.pm.ServiceInfo; import android.os.IBinder; // Foreground service whose only job is to keep the app process alive // while the user is mirroring. Mirror starts it on entry and stops it // in onDestroy; the running foreground service (with its notification) // is what keeps the OOM killer away, so the activity can survive being // briefly backgrounded (rotation, IME, swipe-to-home) without the // scrcpy server tearing down. // // Type is FOREGROUND_SERVICE_DATA_SYNC: we are pulling a continuous // data stream (encoded video + raw PCM) from another device. // // No binder API - the service does not own Session. Mirror owns it. public final class Sessions extends Service { private static final String CHANNEL_ID = "scrcpy-android-session"; private static final int NOTIF_ID = 1; @Override public void onCreate() { super.onCreate(); Log.i("sessions: onCreate"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { ensureChannel(); Notification n = new Notification.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_notification) .setContentTitle(getString(R.string.app_name)) .setContentText(getString(R.string.notif_session_active)) .setContentIntent(reopenIntent()) .setOngoing(true) .build(); startForeground(NOTIF_ID, n, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC); return START_NOT_STICKY; } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { Log.i("sessions: onDestroy"); super.onDestroy(); } private void ensureChannel() { NotificationManager nm = getSystemService(NotificationManager.class); if (nm.getNotificationChannel(CHANNEL_ID) != null) return; NotificationChannel ch = new NotificationChannel( CHANNEL_ID, getString(R.string.app_name), NotificationManager.IMPORTANCE_LOW); ch.setDescription(getString(R.string.notif_session_active)); nm.createNotificationChannel(ch); } private PendingIntent reopenIntent() { Intent i = new Intent(this, Main.class); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); return PendingIntent.getActivity(this, 0, i, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT); } }