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