代码之家  ›  专栏  ›  技术社区  ›  Paul

在服务中实现onActivityResult()

  •  0
  • Paul  · 技术社区  · 7 年前

    我有以下代码,应该使用服务记录设备屏幕。

    问题是,要使用它,我需要使用如下调用: startActivityForResult/onActivityResult ,以便能够录制屏幕。

    但在安卓服务上并没有这样的呼吁。

    我必须这样开始:

    startActivityForResult (mProjectionManager.createScreenCaptureIntent (), CAST_PERMISSION_CODE);
    

    代码:

    public void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode != CAST_PERMISSION_CODE) {
                Log.w("class:", "Unknown request code: " + requestCode);
                return;
            }
            Log.w("class:", "onActivityResult:resultCode");
            if (resultCode != RESULT_OK) {
                startRec = false;
                Toast.makeText(this, "Screen Cast Permission Denied :(", Toast.LENGTH_SHORT).show();
                return;
            }
            prepareRecording("start");
            mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
    
            Log.w("class:", "onActivityResult:mMediaProjection");
    
            // TODO Register a callback that will listen onStop and release & prepare the recorder for next WidgetProvider
            // mMediaProjection.registerCallback(callback, null);
            mVirtualDisplay = getVirtualDisplay();
            mMediaRecorder.start();
        } 
    

    我该如何提出建议?

    完整代码:

    package com.unkinstagram;
    
    import android.app.Notification;
    import android.app.PendingIntent;
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.hardware.display.DisplayManager;
    import android.hardware.display.VirtualDisplay;
    import android.media.MediaRecorder;
    import android.media.projection.MediaProjection;
    import android.media.projection.MediaProjectionManager;
    import android.os.Environment;
    import android.os.IBinder;
    import android.support.v4.app.NotificationCompat;
    import android.util.DisplayMetrics;
    import android.util.Log;
    import android.view.WindowManager;
    import android.widget.Toast;
    
    import java.io.File;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    import static android.app.Activity.RESULT_OK;
    
    class Constants {
        public interface ACTION {
            public static String MAIN_ACTION = "com.unkinstagram.action.main";
            public static String STARTFOREGROUND_ACTION = "com.unkinstagram.action.startforeground";
            public static String STOPFOREGROUND_ACTION = "com.unkinstagram.action.stopforeground";
            public static String REC_ACTION = "com.unkinstagram.action.rec";
            public static String STOP_ACTION = "com.unkinstagram.action.stop";
        }
    
        public interface NOTIFICATION_ID {
            public static int FOREGROUND_SERVICE = 101;
        }
    }
    
    public class ForegroundService extends Service {
        private static final String LOG_TAG = "class:";
    
        private static final int CAST_PERMISSION_CODE = 22;
        private DisplayMetrics mDisplayMetrics;
        private MediaProjection mMediaProjection;
        private VirtualDisplay mVirtualDisplay;
        private MediaRecorder mMediaRecorder;
        private MediaProjectionManager mProjectionManager;
    
        private boolean startRec = false;
    
        @Override
        public void onCreate() {
            super.onCreate();
            mDisplayMetrics = new DisplayMetrics();
            mMediaRecorder = new MediaRecorder();
            mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
            WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
            window.getDefaultDisplay().getMetrics(mDisplayMetrics);
            Log.v(LOG_TAG,"create");
        }
    
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            if (intent.getAction().equals(Constants.ACTION.STARTFOREGROUND_ACTION)) {
                Log.i(LOG_TAG, "Received Start Foreground Intent ");
                Intent notificationIntent = new Intent(this, MainActivity2.class);
                notificationIntent.setAction(Constants.ACTION.MAIN_ACTION);
                notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
    
                Intent recIntent = new Intent(this, ForegroundService.class);
                recIntent.setAction(Constants.ACTION.REC_ACTION);
                PendingIntent pRecIntent = PendingIntent.getService(this, 0, recIntent, 0);
    
                Intent stopIntent = new Intent(this, ForegroundService.class);
                stopIntent.setAction(Constants.ACTION.STOP_ACTION);
                PendingIntent pStopIntent = PendingIntent.getService(this, 0, stopIntent, 0);
    
                Notification notification = new NotificationCompat.Builder(this)
                        .setContentTitle("Stai per registrare lo schermo del device.")
                        .setSmallIcon(R.drawable.ic_videocam_off)
                        .setContentIntent(pendingIntent)
                        .setOngoing(true)
                        .addAction(0, "Rec", pRecIntent)
                        .addAction(0, "Stop", pStopIntent)
                        .build();
                startForeground(Constants.NOTIFICATION_ID.FOREGROUND_SERVICE, notification);
    
            } else if (intent.getAction().equals(Constants.ACTION.REC_ACTION)) {
                Log.i(LOG_TAG, "Clicked Rec");
                startRecording();
            } else if (intent.getAction().equals(Constants.ACTION.STOP_ACTION)) {
                Log.i(LOG_TAG, "Clicked Stop");
                stopRecording();
                stopForeground(true);
                stopSelf();
            } else if (intent.getAction().equals(Constants.ACTION.STOPFOREGROUND_ACTION)) {
                Log.i(LOG_TAG, "Received Stop Foreground Intent");
                stopForeground(true);
                stopSelf();
            }
            return START_STICKY;
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            Log.i(LOG_TAG, "In onDestroy");
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    
        private void startRecording() {
            startRec = true;
            // If mMediaProjection is null that means we didn't get a context, lets ask the user
            Log.w("class:", "startRecording:start");
            if (mMediaProjection == null) {
                // This asks for user permissions to capture the screen
                Log.w("class:", "startRecording:startResult");
                startActivityForResult(mProjectionManager.createScreenCaptureIntent(), CAST_PERMISSION_CODE);
                Log.w("class:", "startRecording:endResult");
                return;
            }
            Log.w("class:", "startRecording:end");
            mVirtualDisplay = getVirtualDisplay();
            mMediaRecorder.start();
        }
    
        private void stopRecording() {
            startRec = false;
            Log.w("class:", "stopRecording:start");
            if (mMediaRecorder != null) {
                mMediaRecorder.stop();
                mMediaRecorder.reset();
                //mMediaRecorder = null;
            }
            if (mVirtualDisplay != null) {
                mVirtualDisplay.release();
                //mVirtualDisplay = null;
            }
            if (mMediaProjection != null) {
                mMediaProjection.stop();
                //mMediaProjection = null;
            }
            Log.w("class:", "stopRecording:end");
        }
    
        public String getCurSysDate() {
            return new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss").format(new Date());
        }
    
        private void prepareRecording(String name) {
            if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
                Toast.makeText(this, "Failed to get External Storage", Toast.LENGTH_SHORT).show();
                return;
            }
            final String directory = Environment.getExternalStorageDirectory() + File.separator + "Recordings";
            final File folder = new File(directory);
            boolean success = true;
            if (!folder.exists()) {
                success = folder.mkdir();
            }
            if (!success) {
                Toast.makeText(this, "Failed to create Recordings directory", Toast.LENGTH_SHORT).show();
                return;
            }
    
            String videoName = (name + "_" + getCurSysDate() + ".mp4");
            String filePath = directory + File.separator + videoName;
    
            int width = mDisplayMetrics.widthPixels;
            int height = mDisplayMetrics.heightPixels;
    
            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            mMediaRecorder.setVideoEncodingBitRate(8000 * 1000);
            mMediaRecorder.setVideoFrameRate(24);
            mMediaRecorder.setVideoSize(width, height);
            mMediaRecorder.setOutputFile(filePath);
    
            try {
                mMediaRecorder.prepare();
            } catch (Exception e) {
                e.printStackTrace();
                return;
            }
    
        }
    
        private VirtualDisplay getVirtualDisplay() {
            int screenDensity = mDisplayMetrics.densityDpi;
            int width = mDisplayMetrics.widthPixels;
            int height = mDisplayMetrics.heightPixels;
            return mMediaProjection.createVirtualDisplay(this.getClass().getSimpleName(),
                    width, height, screenDensity,
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                    mMediaRecorder.getSurface(), null, null);
        }
    
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            if (requestCode != CAST_PERMISSION_CODE) {
                Log.w("class:", "Unknown request code: " + requestCode);
                return;
            }
            Log.w("class:", "onActivityResult:resultCode");
            if (resultCode != RESULT_OK) {
                startRec = false;
                Toast.makeText(this, "Screen Cast Permission Denied :(", Toast.LENGTH_SHORT).show();
                return;
            }
            prepareRecording("start");
            mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
    
            Log.w("class:", "onActivityResult:mMediaProjection");
    
            // TODO Register a callback that will listen onStop and release & prepare the recorder for next WidgetProvider
            // mMediaProjection.registerCallback(callback, null);
            mVirtualDisplay = getVirtualDisplay();
            mMediaRecorder.start();
        }
    }
    
    2 回复  |  直到 7 年前
        1
  •  1
  •   Dewey Reed    7 年前

    因此,您希望在服务中使用MediaProjection。要使用MediaProjection,您需要用户授予权限,然后使用onActivityResult中返回的意图创建MediaProjection。但是,您在服务中,没有可用的onActivityResult。

    下面是一个有用的github问题: https://github.com/mtsahakis/MediaProjectionDemo/issues/7 . 还有一些GIST可以使用。

    基本思想是使用一个活动来请求许可,然后用一个包含结果意图的意图启动您的服务(意图也是可划分的,因此可以放入另一个意图中)。

        2
  •  1
  •   CommonsWare    7 年前

    虽然服务可以参与屏幕录制,但必须从活动中获得许可。因此,在开始服务之前,请先获得许可。

    例如,在 this sample app 虽然 the RecorderService 实际上是启动和停止屏幕录制, the MainActivity 是在启动该服务之前请求权限的内容。该活动使用 Theme.Translucent.NoTitleBar