Tout organisme sait pourquoi cette erreur se produit, les projections de médias nécessitent un service de premier plan de type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION sur getMediaProjection () même j'appelle la méthode getMediaProjection () après avoir appelé la méthode startforeground () ..!

Stack Trace est:

  Process: com.al1.screenrecorder, PID: 24641
java.lang.RuntimeException: Unable to start service com.al1.screenrecorder.service.DisplayRecorderService@9ef2101 with Intent { cmp=com.al1.screenrecorder/.service.DisplayRecorderService (has extras) }: java.lang.SecurityException: Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4661)
    at android.app.ActivityThread.access$2900(ActivityThread.java:292)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2246)
    at android.os.Handler.dispatchMessage(Handler.java:107)
    at android.os.Looper.loop(Looper.java:213)
    at android.app.ActivityThread.main(ActivityThread.java:8147)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101)
 Caused by: java.lang.SecurityException: Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
    at android.os.Parcel.createException(Parcel.java:2071)
    at android.os.Parcel.readException(Parcel.java:2039)
    at android.os.Parcel.readException(Parcel.java:1987)
    at android.media.projection.IMediaProjection$Stub$Proxy.start(IMediaProjection.java:231)
    at android.media.projection.MediaProjection.<init>(MediaProjection.java:75)
    at android.media.projection.MediaProjectionManager.getMediaProjection(MediaProjectionManager.java:104)
    at com.al1.screenrecorder.service.DisplayRecorderService.createMediaProjection(DisplayRecorderService.java:118)
    at com.al1.screenrecorder.service.DisplayRecorderService.onStartCommand(DisplayRecorderService.java:107)
    at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:4641)
    at android.app.ActivityThread.access$2900(ActivityThread.java:292) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2246) 
    at android.os.Handler.dispatchMessage(Handler.java:107) 
    at android.os.Looper.loop(Looper.java:213) 
    at android.app.ActivityThread.main(ActivityThread.java:8147) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1101) 
 Caused by: android.os.RemoteException: Remote stack trace:
    at com.android.server.media.projection.MediaProjectionManagerService$MediaProjection.start(MediaProjectionManagerService.java:498)
    at android.media.projection.IMediaProjection$Stub.onTransact(IMediaProjection.java:135)
    at android.os.Binder.execTransactInternal(Binder.java:1028)
    at android.os.Binder.execTransact(Binder.java:1001)

texte fort private void startForeground () {

    Intent activityIntent = new Intent(this, MainActivity.class);
    activityIntent.setAction("stop");
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, activityIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

        String channelId = "001";
        String channelName = "myChannel";
        NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_NONE);
        channel.setLightColor(Color.BLUE);
        channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);

        NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        if (manager != null) {
            manager.createNotificationChannel(channel);
            Notification notification = new Notification.
                    Builder(getApplicationContext(), channelId)
                    .setOngoing(true)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setCategory(Notification.CATEGORY_SERVICE)
                    .setContentTitle(getString(R.string.ClickToCancel))
                    .setContentIntent(contentIntent)
                    .build();
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                startForeground(0, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION);
            } else {
                startForeground(0, notification);
            }
        }
    } else {
        startForeground(0, new Notification());
    }

}

Et onStartCommand est:

public int onStartCommand(Intent intent, int flags, int startId) {
    Log.i(TAG, "Service onStartCommand() is called");

    startForeground();

    mResultCode = intent.getIntExtra("code", -1);
    mResultData = intent.getParcelableExtra("data");
    mScreenWidth = intent.getIntExtra("width", 720);
    mScreenHeight = intent.getIntExtra("height", 1280);
    mScreenDensity = intent.getIntExtra("density", 1);
    isVideoSd = intent.getBooleanExtra("quality", true);
    isAudio = intent.getBooleanExtra("audio", true);


    mMediaProjection = createMediaProjection();
    mMediaRecorder = createMediaRecorder();
    mVirtualDisplay = createVirtualDisplay();
    mMediaRecorder.start();

    return Service.START_STICKY;
}

Et l'exception est dans cette méthode sur getMediaProjection:

 private MediaProjection createMediaProjection() {
    Log.i(TAG, "Create MediaProjection");
    return ((MediaProjectionManager) Objects.requireNonNull(getSystemService(Context.MEDIA_PROJECTION_SERVICE))).
            getMediaProjection(mResultCode, mResultData);
}
7
Mirza Ali 17 avril 2020 à 19:53

5 réponses

Veuillez vous assurer que vous avez accordé les autorisations FOREGROUND_SERVICE requises. Si votre targetSdkVersion = 28 utilisant les services de premier plan doit demander l'autorisation FOREGROUND_SERVICE . Ajoutez donc l'autorisation FOREGROUND_SERVICE à votre fichier manifeste sans laquelle il lance SecurityException .

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Vous pouvez en savoir plus sur ces notes de migration: https: // développeur .android.com / about / versions / pie / android-9.0-migration # tya peut lire dans cette capture d'écran

J'espère que cela vous aidera.....

1
Android_id 18 avril 2020 à 08:42

Ajoutez android:foregroundServiceType="mediaProjection" à l'élément <service> dans le manifeste de votre service.

14
CommonsWare 17 avril 2020 à 17:11

Après avoir ajouté l'autorisation de premier plan <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />, vous devez créer une classe de service. Ainsi, dans un nouveau fichier Java, procédez comme suit:

public class BackgroundService extends Service {

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        createNotificationChannel();
        Intent intent1 = new Intent(this, ClassWithError.class);
        Intent intent2 = new Intent(this, AnotherClassWithError.class);

        PendingIntent pendingIntent1 = PendingIntent.getActivity(this, 0, intent1, 0);
        PendingIntent pendingIntent2 = PendingIntent.getActivity(this, 0, intent2, 0);

        Notification notification1 = new NotificationCompat.Builder(this, "ScreenRecorder")
                .setContentTitle("yNote studios")
                .setContentText("Filming...")
                .setContentIntent(pendingIntent1).build();

        Notification notification2 = new NotificationCompat.Builder(this, "ScreenRecorder")
                .setContentTitle("yNote studios")
                .setContentText("Filming...")
                .setContentIntent(pendingIntent1).build();

        startForeground(1, notification1);
        startForeground(2, notification2);
        return super.onStartCommand(intent, flags, startId);
    }


    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            NotificationChannel channel = new NotificationChannel("ScreenRecorder", "Foreground notification",
                    NotificationManager.IMPORTANCE_DEFAULT);
            NotificationManager manager = getSystemService(NotificationManager.class);
            manager.createNotificationChannel(channel);
        }
    }

    @Override
    public void onDestroy() {
        stopForeground(true);
        stopSelf();

        super.onDestroy();
    }
}

Puis de retour dans le manifeste, ajoutez le segment de service avec la section de nom comme classe de service ci-dessus. Il doit faire partie du segment d'application.

<service
            android:name=".Services.BackgroundService"
            android:enabled="true"
            android:exported="true"
            android:stopWithTask="true"
            android:foregroundServiceType="mediaProjection" />

Après l'avoir configuré comme ça, vous pouvez accéder à ce service d'arrière-plan chaque fois que vous en avez besoin (dans la méthode onCreate) comme suit:

Intent intent = new Intent(this, BackgroundService.class);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForegroundService(intent);
        } else {
            startService(intent);
        }

Mais assurez-vous de le gérer. Cela peut être à l'origine de plusieurs exceptions dans d'autres fonctions de votre projet. Des éléments tels que les enregistreurs multimédias seront écrasés lorsqu'ils sont appelés pendant que ce service est en cours d'exécution. Pour cela, utilisez la méthode onDestroy pour fermer le service.

0
Orwa Ogwari 21 janv. 2021 à 08:59

Vous devez démarrer un service de premier plan avant de créer une projection multimédia.

Si vous disposez déjà d'un service, il y aura un délai pour démarrer le service la plupart du temps, même si vous démarrez le service avant d'initialiser la projection multimédia. Démarrez la projection après un léger délai après le démarrage du service. Je pense que cela fera l'affaire.

Exemple de code:

startService(new Intent(AppController.getInstance(),
            ScreenCaptureService.class));

 new Handler().postDelayed(new Runnable() {
        @Override
        public void run() {
            MediaProjectionManager projectionManager = (MediaProjectionManager)
                    context.getSystemService(Context.MEDIA_PROJECTION_SERVICE);

           if (isServiceActive(context, ScreenCaptureService.class)){
               mMediaProjection =
                       projectionManager.getMediaProjection(resultCode, data);
               processAndSaveScreenshotFromDevice(context);
           }
        }
    }, 200);
0
Abhijith Brumal 19 janv. 2021 à 09:41

Emballer getMediaProjection(mResultCode, mResultData) dans un Handler().postDelayed() a résolu le problème pour moi.

override fun onServiceConnected(className: ComponentName, service: IBinder) {
        // We've bound to LocalService, cast the IBinder and get LocalService instance
        val binder = service as MediaProjectionService.LocalBinder
        mediaProjectionService = binder.getService()

        // delay needed because getMediaProjection() throws an error if it's called too soon
        Handler().postDelayed({
            mediaProjection = mediaProjectionManager.getMediaProjection(activityResultCode, activityData)
            startStreaming()
            serviceBound = true
        }, 1000)
    }
1
f4b 24 août 2020 à 08:16