package com.serenegiant.screenrecordingsample; /* * ScreenRecordingSample * Sample project to cature and save audio from internal and video from screen as MPEG4 file. * * Copyright (c) 2015 saki t_saki@serenegiant.com * * File name: MainActivity.java * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * All files in the folder are under this Apache License, Version 2.0. */ import java.lang.ref.WeakReference; import android.Manifest; import android.annotation.SuppressLint; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.media.projection.MediaProjectionManager; import android.os.Bundle; import android.support.annotation.NonNull; import android.util.Log; import android.widget.CompoundButton; import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.Toast; import android.widget.ToggleButton; import com.serenegiant.dialog.MessageDialogFragment; import com.serenegiant.service.ScreenRecorderService; import com.serenegiant.utils.BuildCheck; import com.serenegiant.utils.PermissionCheck; public final class MainActivity extends Activity implements MessageDialogFragment.MessageDialogListener { private static final boolean DEBUG = false; private static final String TAG = "MainActivity"; private static final int REQUEST_CODE_SCREEN_CAPTURE = 1; private ToggleButton mRecordButton; private ToggleButton mPauseButton; private MyBroadcastReceiver mReceiver; @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (DEBUG) Log.v(TAG, "onCreate:"); setContentView(R.layout.activity_main); mRecordButton = (ToggleButton)findViewById(R.id.record_button); mPauseButton = (ToggleButton)findViewById(R.id.pause_button); updateRecording(false, false); if (mReceiver == null) { mReceiver = new MyBroadcastReceiver(this); } } @Override protected void onResume() { super.onResume(); if (DEBUG) Log.v(TAG, "onResume:"); final IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(ScreenRecorderService.ACTION_QUERY_STATUS_RESULT); registerReceiver(mReceiver, intentFilter); queryRecordingStatus(); } @Override protected void onPause() { if (DEBUG) Log.v(TAG, "onPause:"); unregisterReceiver(mReceiver); super.onPause(); } @Override protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) { if (DEBUG) Log.v(TAG, "onActivityResult:resultCode=" + resultCode + ",data=" + data); super.onActivityResult(requestCode, resultCode, data); if (REQUEST_CODE_SCREEN_CAPTURE == requestCode) { if (resultCode != Activity.RESULT_OK) { // when no permission Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show(); return; } startScreenRecorder(resultCode, data); } } private final OnCheckedChangeListener mOnCheckedChangeListener = new OnCheckedChangeListener() { @Override public void onCheckedChanged(final CompoundButton buttonView, final boolean isChecked) { switch (buttonView.getId()) { case R.id.record_button: if (checkPermissionWriteExternalStorage() && checkPermissionAudio()) { if (isChecked) { final MediaProjectionManager manager = (MediaProjectionManager)getSystemService(Context.MEDIA_PROJECTION_SERVICE); final Intent permissionIntent = manager.createScreenCaptureIntent(); startActivityForResult(permissionIntent, REQUEST_CODE_SCREEN_CAPTURE); } else { final Intent intent = new Intent(MainActivity.this, ScreenRecorderService.class); intent.setAction(ScreenRecorderService.ACTION_STOP); startService(intent); } } else { mRecordButton.setOnCheckedChangeListener(null); try { mRecordButton.setChecked(false); } finally { mRecordButton.setOnCheckedChangeListener(mOnCheckedChangeListener); } } break; case R.id.pause_button: if (isChecked) { final Intent intent = new Intent(MainActivity.this, ScreenRecorderService.class); intent.setAction(ScreenRecorderService.ACTION_PAUSE); startService(intent); } else { final Intent intent = new Intent(MainActivity.this, ScreenRecorderService.class); intent.setAction(ScreenRecorderService.ACTION_RESUME); startService(intent); } break; } } }; private void queryRecordingStatus() { if (DEBUG) Log.v(TAG, "queryRecording:"); final Intent intent = new Intent(this, ScreenRecorderService.class); intent.setAction(ScreenRecorderService.ACTION_QUERY_STATUS); startService(intent); } private void startScreenRecorder(final int resultCode, final Intent data) { final Intent intent = new Intent(this, ScreenRecorderService.class); intent.setAction(ScreenRecorderService.ACTION_START); intent.putExtra(ScreenRecorderService.EXTRA_RESULT_CODE, resultCode); intent.putExtras(data); startService(intent); } private void updateRecording(final boolean isRecording, final boolean isPausing) { if (DEBUG) Log.v(TAG, "updateRecording:isRecording=" + isRecording + ",isPausing=" + isPausing); mRecordButton.setOnCheckedChangeListener(null); mPauseButton.setOnCheckedChangeListener(null); try { mRecordButton.setChecked(isRecording); mPauseButton.setEnabled(isRecording); mPauseButton.setChecked(isPausing); } finally { mRecordButton.setOnCheckedChangeListener(mOnCheckedChangeListener); mPauseButton.setOnCheckedChangeListener(mOnCheckedChangeListener); } } private static final class MyBroadcastReceiver extends BroadcastReceiver { private final WeakReference<MainActivity> mWeakParent; public MyBroadcastReceiver(final MainActivity parent) { mWeakParent = new WeakReference<MainActivity>(parent); } @Override public void onReceive(final Context context, final Intent intent) { if (DEBUG) Log.v(TAG, "onReceive:" + intent); final String action = intent.getAction(); if (ScreenRecorderService.ACTION_QUERY_STATUS_RESULT.equals(action)) { final boolean isRecording = intent.getBooleanExtra(ScreenRecorderService.EXTRA_QUERY_RESULT_RECORDING, false); final boolean isPausing = intent.getBooleanExtra(ScreenRecorderService.EXTRA_QUERY_RESULT_PAUSING, false); final MainActivity parent = mWeakParent.get(); if (parent != null) { parent.updateRecording(isRecording, isPausing); } } } } //================================================================================ // methods related to new permission model on Android 6 and later //================================================================================ /** * Callback listener from MessageDialogFragmentV4 * @param dialog * @param requestCode * @param permissions * @param result */ @SuppressLint("NewApi") @Override public void onMessageDialogResult(final MessageDialogFragment dialog, final int requestCode, final String[] permissions, final boolean result) { if (result) { // request permission(s) when user touched/clicked OK if (BuildCheck.isMarshmallow()) { requestPermissions(permissions, requestCode); return; } } // check permission and call #checkPermissionResult when user canceled or not Android6(and later) for (final String permission: permissions) { checkPermissionResult(requestCode, permission, PermissionCheck.hasPermission(this, permission)); } } /** * callback method when app(Fragment) receive the result of permission result from ANdroid system * @param requestCode * @param permissions * @param grantResults */ @Override public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, @NonNull final int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); // 何もしてないけど一応呼んどく final int n = Math.min(permissions.length, grantResults.length); for (int i = 0; i < n; i++) { checkPermissionResult(requestCode, permissions[i], grantResults[i] == PackageManager.PERMISSION_GRANTED); } } /** * check the result of permission request * if app still has no permission, just show Toast * @param requestCode * @param permission * @param result */ protected void checkPermissionResult(final int requestCode, final String permission, final boolean result) { // show Toast when there is no permission if (Manifest.permission.RECORD_AUDIO.equals(permission)) { onUpdateAudioPermission(result); if (!result) { Toast.makeText(this, R.string.permission_audio, Toast.LENGTH_SHORT).show(); } } if (Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) { onUpdateExternalStoragePermission(result); if (!result) { Toast.makeText(this, R.string.permission_ext_storage, Toast.LENGTH_SHORT).show(); } } if (Manifest.permission.INTERNET.equals(permission)) { onUpdateNetworkPermission(result); if (!result) { Toast.makeText(this, R.string.permission_network, Toast.LENGTH_SHORT).show(); } } } /** * called when user give permission for audio recording or canceled * @param hasPermission */ protected void onUpdateAudioPermission(final boolean hasPermission) { } /** * called when user give permission for accessing external storage or canceled * @param hasPermission */ protected void onUpdateExternalStoragePermission(final boolean hasPermission) { } /** * called when user give permission for accessing network or canceled * this will not be called * @param hasPermission */ protected void onUpdateNetworkPermission(final boolean hasPermission) { } protected static final int REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE = 0x01; protected static final int REQUEST_PERMISSION_AUDIO_RECORDING = 0x02; protected static final int REQUEST_PERMISSION_NETWORK = 0x03; /** * check whether this app has write external storage * if this app has no permission, show dialog * @return true this app has permission */ protected boolean checkPermissionWriteExternalStorage() { if (!PermissionCheck.hasWriteExternalStorage(this)) { MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_WRITE_EXTERNAL_STORAGE, R.string.permission_title, R.string.permission_ext_storage_request, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}); return false; } return true; } /** * check whether this app has permission of audio recording * if this app has no permission, show dialog * @return true this app has permission */ protected boolean checkPermissionAudio() { if (!PermissionCheck.hasAudio(this)) { MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_AUDIO_RECORDING, R.string.permission_title, R.string.permission_audio_recording_request, new String[]{Manifest.permission.RECORD_AUDIO}); return false; } return true; } /** * check whether permission of network access * if this app has no permission, show dialog * @return true this app has permission */ protected boolean checkPermissionNetwork() { if (!PermissionCheck.hasNetwork(this)) { MessageDialogFragment.showDialog(this, REQUEST_PERMISSION_NETWORK, R.string.permission_title, R.string.permission_network_request, new String[]{Manifest.permission.INTERNET}); return false; } return true; } }