如何只使用MediaProjectionManager屏幕获取权限一次而不是每次使用?

时间:2017-02-07 05:41:00

标签: android android-mediaprojection

public class MainActivity extends AppCompatActivity {

private static final String TAG = "MainActivity";
private static final int REQUEST_CODE = 1234;
private int mScreenDensity;
private MediaProjectionManager mProjectionManager;
private static final int DISPLAY_WIDTH = 720;
private static final int DISPLAY_HEIGHT = 1280;
private MediaProjection mMediaProjection;
private VirtualDisplay mVirtualDisplay;
private ToggleButton mToggleButton;
private MediaRecorder mMediaRecorder;
private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
private static final int REQUEST_PERMISSIONS = 10;

static {
    ORIENTATIONS.append(Surface.ROTATION_0, 90);
    ORIENTATIONS.append(Surface.ROTATION_90, 0);
    ORIENTATIONS.append(Surface.ROTATION_180, 270);
    ORIENTATIONS.append(Surface.ROTATION_270, 180);
}

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);
    mScreenDensity = metrics.densityDpi;


    mProjectionManager = (MediaProjectionManager) getSystemService
            (Context.MEDIA_PROJECTION_SERVICE);

    mToggleButton = (ToggleButton) findViewById(R.id.toggle);
    mToggleButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            if (ContextCompat.checkSelfPermission(MainActivity.this,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE) + ContextCompat
                    .checkSelfPermission(MainActivity.this,
                            Manifest.permission.RECORD_AUDIO)
                    != PackageManager.PERMISSION_GRANTED) {
                if (ActivityCompat.shouldShowRequestPermissionRationale
                        (MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ||
                        ActivityCompat.shouldShowRequestPermissionRationale
                                (MainActivity.this, Manifest.permission.RECORD_AUDIO)) {
                    mToggleButton.setChecked(false);
                    Snackbar.make(findViewById(android.R.id.content), R.string.label_permissions,
                            Snackbar.LENGTH_INDEFINITE).setAction("ENABLE",
                            new View.OnClickListener() {
                                @Override
                                public void onClick(View v) {
                                    ActivityCompat.requestPermissions(MainActivity.this,
                                            new String[]{Manifest.permission
                                                    .WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO},
                                            REQUEST_PERMISSIONS);
                                }
                            }).show();
                } else {
                    ActivityCompat.requestPermissions(MainActivity.this,
                            new String[]{Manifest.permission
                                    .WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO},
                            REQUEST_PERMISSIONS);
                }
            } else {
                onToggleScreenShare(v);
            }
        }
    });
}

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {

    Log.d(TAG, " requestCode " + requestCode + " resultCode " + requestCode);

    if (REQUEST_CODE == requestCode) {
        if (resultCode == RESULT_OK) {
            mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
            startRecording(); // defined below
        } else {
            Log.d(TAG, "Persmission denied");
        }
    }
}

private static final String VIDEO_MIME_TYPE = "video/avc";
private static final int VIDEO_WIDTH = 720;
private static final int VIDEO_HEIGHT = 1280;
// …
private boolean mMuxerStarted = false;
private Surface mInputSurface;
private MediaMuxer mMuxer;
private MediaCodec mVideoEncoder;
private MediaCodec.BufferInfo mVideoBufferInfo;
private int mTrackIndex = -1;

private final Handler mDrainHandler = new Handler(Looper.getMainLooper());
private Runnable mDrainEncoderRunnable = new Runnable() {
    @Override
    public void run() {
        drainEncoder();
    }
};

private void startRecording() {

    DisplayManager dm = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
    Display defaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
    if (defaultDisplay == null) {
        throw new RuntimeException("No display found.");
    }
    prepareVideoEncoder();

    try {
        mMuxer = new MediaMuxer(Environment.getExternalStoragePublicDirectory(Environment
                .DIRECTORY_DOWNLOADS) + "/video.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
    } catch (IOException ioe) {
        throw new RuntimeException("MediaMuxer creation failed", ioe);
    }

    // Get the display size and density.
    DisplayMetrics metrics = getResources().getDisplayMetrics();
    int screenWidth = metrics.widthPixels;
    int screenHeight = metrics.heightPixels;
    int screenDensity = metrics.densityDpi;

    // Start the video input.
    mMediaProjection.createVirtualDisplay("Recording Display", screenWidth,
            screenHeight, screenDensity, 0 /* flags */, mInputSurface,
            null /* callback */, null /* handler */);

    // Start the encoders
    drainEncoder();
}

private void prepareVideoEncoder() {

    mVideoBufferInfo = new MediaCodec.BufferInfo();
    MediaFormat format = MediaFormat.createVideoFormat(VIDEO_MIME_TYPE, VIDEO_WIDTH, VIDEO_HEIGHT);
    int frameRate = 15; // 30 fps

    // Set some required properties. The media codec may fail if these aren't defined.
    format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
    //format.setInteger(MediaFormat.KEY_SAMPLE_RATE, 8000);
    format.setInteger(MediaFormat.KEY_BIT_RATE, 6000000); // 6Mbps
    format.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
    //format.setInteger(MediaFormat.KEY_CAPTURE_RATE, frameRate);
    // format.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 1000000 / frameRate);
    //format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
    format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10); // 1 seconds between I-frames

    // Create a MediaCodec encoder and configure it. Get a Surface we can use for recording into.
    try {
        mVideoEncoder = MediaCodec.createEncoderByType(VIDEO_MIME_TYPE);
        mVideoEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
        mInputSurface = mVideoEncoder.createInputSurface();
        mVideoEncoder.start();
    } catch (IOException e) {
        releaseEncoders();
    }
}

private void releaseEncoders() {


    mDrainHandler.removeCallbacks(mDrainEncoderRunnable);
    if (mMuxer != null) {
        if (mMuxerStarted) {
            mMuxer.stop();
        }
        mMuxer.release();
        mMuxer = null;
        mMuxerStarted = false;
    }
    if (mVideoEncoder != null) {
        mVideoEncoder.stop();
        mVideoEncoder.release();
        mVideoEncoder = null;
    }
    if (mInputSurface != null) {
        mInputSurface.release();
        mInputSurface = null;
    }
    if (mMediaProjection != null) {
        mMediaProjection.stop();
        mMediaProjection = null;
    }
    mVideoBufferInfo = null;
    //mDrainEncoderRunnable = null;
    mTrackIndex = -1;
}

private boolean drainEncoder() {
    mDrainHandler.removeCallbacks(mDrainEncoderRunnable);
    while (true) {
        int bufferIndex = mVideoEncoder.dequeueOutputBuffer(mVideoBufferInfo, 0);

        if (bufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
            // nothing available yet
            break;
        } else if (bufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
            // should happen before receiving buffers, and should only happen once
            if (mTrackIndex >= 0) {
                throw new RuntimeException("format changed twice");
            }
            mTrackIndex = mMuxer.addTrack(mVideoEncoder.getOutputFormat());
            if (!mMuxerStarted && mTrackIndex >= 0) {
                mMuxer.start();
                mMuxerStarted = true;
            }
        } else if (bufferIndex < 0) {
            // not sure what's going on, ignore it
        } else {
            ByteBuffer encodedData = mVideoEncoder.getOutputBuffer(bufferIndex);
            if (encodedData == null) {
                throw new RuntimeException("couldn't fetch buffer at index " + bufferIndex);
            }

            if ((mVideoBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
                mVideoBufferInfo.size = 0;
            }

            if (mVideoBufferInfo.size != 0) {
                if (mMuxerStarted) {
                    encodedData.position(mVideoBufferInfo.offset);
                    encodedData.limit(mVideoBufferInfo.offset + mVideoBufferInfo.size);
                    mMuxer.writeSampleData(mTrackIndex, encodedData, mVideoBufferInfo);
                } else {
                    // muxer not started
                }
            }

            mVideoEncoder.releaseOutputBuffer(bufferIndex, false);

            if ((mVideoBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                break;
            }
        }
        Log.d(TAG, "Recording");
    }

    mDrainHandler.postDelayed(mDrainEncoderRunnable, 10);

    return false;
}


public void onToggleScreenShare(View view) {
    if (((ToggleButton) view).isChecked()) {
        if (mMediaProjection == null) {
            startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);
        } else {
            startRecording();
        }
    } else {
        releaseEncoders();
    }
}

}

startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);

此行代码请求捕获屏幕的权限。每次我的代码调用它并显示一个权限对话框。但如果我点击“不再显示此内容”,它将不会请求权限,而是在后台授予权限。我怎么能只获得一次许可并且无需选择再次显示所有时间?完整代码在这里给出

1 个答案:

答案 0 :(得分:1)

public void onToggleScreenShare(View view) {
if (((ToggleButton) view).isChecked()) {
    if (mMediaProjection == null) {
        startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);
    } else {
        startRecording();
    }
} else {
    releaseEncoders();
}
}

在此方法startActivityForResult()方法提示屏幕捕获权限。如果授予权限或拒绝代码转移调用onActivityResultMethod()

    @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {

Log.d(TAG, " requestCode " + requestCode + " resultCode " + requestCode);

if (REQUEST_CODE == requestCode) {
    if (resultCode == RESULT_OK) {
        mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
        startRecording(); // defined below
    } else {
        Log.d(TAG, "Persmission denied");
    }
}
}

在这个方法中,我们得到了Intent数据和resultCode。为了在不请求连续许可的情况下进一步使用MediaProjectionManager,我们必须保存Intent的引用和resultCode的值,并通过这行代码使用mediaProjectionManager

mMediaProjection = mProjectionManager.getMediaProjection(saveResult, savedIntent);

因为已经授予了权限,所以它不会再次请求权限