diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser
index 753c055..0868703 100644
Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 3681459..393523c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,11 +1,11 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 28
+ compileSdkVersion 27
defaultConfig {
applicationId "com.deltaforce.siliconcupcake.x11screenrecorder"
minSdkVersion 21
- targetSdkVersion 28
+ targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
@@ -20,9 +20,10 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
- implementation 'com.android.support:appcompat-v7:28.0.0-beta01'
+ implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
+ implementation 'com.android.support:design:27.1.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ab170d1..4646ef3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,6 +1,10 @@
+
+
+
+
= Build.VERSION_CODES.M && context != null && permissions != null) {
+ for (String permission : permissions) {
+ if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/app/src/main/java/com/deltaforce/siliconcupcake/x11screenrecorder/MainActivity.java b/app/src/main/java/com/deltaforce/siliconcupcake/x11screenrecorder/MainActivity.java
index 2fa7fc1..4cd69c9 100644
--- a/app/src/main/java/com/deltaforce/siliconcupcake/x11screenrecorder/MainActivity.java
+++ b/app/src/main/java/com/deltaforce/siliconcupcake/x11screenrecorder/MainActivity.java
@@ -1,13 +1,267 @@
package com.deltaforce.siliconcupcake.x11screenrecorder;
+import android.Manifest;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.PackageManager;
+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.net.Uri;
+import android.os.Environment;
+import android.provider.Settings;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.design.widget.Snackbar;
+import android.support.v4.app.ActivityCompat;
+import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.util.SparseIntArray;
+import android.view.Surface;
+import android.view.View;
+import android.widget.Toast;
+import android.widget.ToggleButton;
+
+import java.io.IOException;
public class MainActivity extends AppCompatActivity {
+ private static final String TAG = "MainActivity";
+ private static final int REQUEST_CODE = 1000;
+ public ToggleButton toggleButton;
+ public boolean isRecording = false;
+ private int mScreenDensity;
+ private MediaProjectionManager mProjectionManager;//manages MediaProjection objects;
+ private static final int DISPLAY_WIDTH = 720;
+ private static final int DISPLAY_HEIGHT = 1280;
+ private MediaProjection mMediaProjection;//token grants ability to capture screen content;
+ private VirtualDisplay mVirtualDisplay;
+ private MediaProjectionCallback mMediaProjectionCallback;
+ public MediaRecorder mMediaRecorder;
+ private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
+ private static final int REQUEST_PERMISSION_KEY = 1;
+ private int counter = 0;
+
+ 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
- protected void onCreate(Bundle savedInstanceState) {
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
+ SharedPreferences prefs = getSharedPreferences("MyPref", MODE_PRIVATE);
+ counter = prefs.getInt("counter" , 0);
+ final String[] PERMISSIONS = {
+ Manifest.permission.WRITE_EXTERNAL_STORAGE,
+ Manifest.permission.READ_EXTERNAL_STORAGE,
+ Manifest.permission.RECORD_AUDIO
+ };
+ Log.d("write permission", PERMISSIONS[0]);
+ Log.d("read permission", PERMISSIONS[1]);
+ if (!Function.hasPermissions(MainActivity.this, PERMISSIONS)) {
+ ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS, REQUEST_PERMISSION_KEY);
+ }
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ mScreenDensity = metrics.densityDpi;
+ mMediaRecorder = new MediaRecorder();
+ mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
+ toggleButton = (ToggleButton) findViewById(R.id.toggleButton);
+ toggleButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+
+
+ onToggleScreenShare();
+
+
+ }
+ });
+
+
+ }
+
+ public void onToggleScreenShare() {
+
+
+ if (!isRecording) {
+ initRecorder();
+ shareScreen();
+ } else {
+ mMediaRecorder.stop();
+ mMediaRecorder.reset();
+ stopScreenSharing();
+ }
+
+
+ }
+
+
+ private void initRecorder() {
+ try {
+ mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
+ mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
+ mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); //THREE_GPP
+ mMediaRecorder.setOutputFile(Environment
+ .getExternalStoragePublicDirectory(Environment
+ .DIRECTORY_DOWNLOADS) + "/video"+String.valueOf(counter)+".mp4");
+ counter++;
+ SharedPreferences pref = getApplicationContext().getSharedPreferences("MyPref", MODE_PRIVATE);
+ SharedPreferences.Editor editor = pref.edit();
+ editor.putInt("counter" , counter);
+ editor.commit();
+ mMediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
+ mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
+ mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
+ mMediaRecorder.setVideoEncodingBitRate(512 * 1000);
+ mMediaRecorder.setVideoFrameRate(16); // 30
+ mMediaRecorder.setVideoEncodingBitRate(3000000);
+ int rotation = getWindowManager().getDefaultDisplay().getRotation();
+ int orientation = ORIENTATIONS.get(rotation + 90);
+ mMediaRecorder.setOrientationHint(orientation);
+ mMediaRecorder.prepare();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private void shareScreen() {
+ if (mMediaProjection == null) {
+ startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);//permission to record screen!
+ return;
+ }
+ mVirtualDisplay = createVirtualDisplay();
+ mMediaRecorder.start();
+ isRecording = true;
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode != REQUEST_CODE) {
+ Log.e(TAG, "Unknown request code: " + requestCode);
+ return;
+ }
+ if (resultCode != RESULT_OK) {
+ Toast.makeText(this, "Screen Cast Permission Denied", Toast.LENGTH_SHORT).show();
+ isRecording = false;
+ toggleButton.setChecked(false);
+ mMediaRecorder = new MediaRecorder();
+ return;
+ }
+ Log.d("REQUEST_CODE", String.valueOf(REQUEST_CODE));
+ mMediaProjectionCallback = new MediaProjectionCallback();
+ mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
+ mMediaProjection.registerCallback(mMediaProjectionCallback, null);
+ mVirtualDisplay = createVirtualDisplay();
+ mMediaRecorder.start();
+ isRecording = true;
+ toggleButton.setChecked(true);
+ }
+
+ private VirtualDisplay createVirtualDisplay() {
+ return mMediaProjection.createVirtualDisplay("MainActivity", DISPLAY_WIDTH, DISPLAY_HEIGHT, mScreenDensity,
+ DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mMediaRecorder.getSurface(), null, null);
+ }
+
+
+ private void stopScreenSharing() {
+ if (mVirtualDisplay == null) {
+ return;
+ }
+ mVirtualDisplay.release();
+ destroyMediaProjection();
+ isRecording = false;
+ toggleButton.setChecked(false);
+ }
+
+ private void destroyMediaProjection() {
+ if (mMediaProjection != null) {
+ mMediaProjection.unregisterCallback(mMediaProjectionCallback);
+ mMediaProjection.stop();
+ mMediaProjection = null;
+ }
+ Log.i(TAG, "MediaProjection Stopped");
+ }
+
+ private class MediaProjectionCallback extends MediaProjection.Callback {
+ @Override
+ public void onStop() {
+ if (isRecording) {
+ isRecording = false;
+ toggleButton.setChecked(false);
+ mMediaRecorder.stop();
+ mMediaRecorder.reset();
+ }
+ mMediaProjection = null;
+ stopScreenSharing();
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ destroyMediaProjection();
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (isRecording) {
+ Snackbar.make(findViewById(android.R.id.content), "Wanna Stop recording and exit?",
+ Snackbar.LENGTH_INDEFINITE).setAction("Stop",
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mMediaRecorder.stop();
+ mMediaRecorder.reset();
+ Log.v(TAG, "Stopping Recording");
+ stopScreenSharing();
+ finish();
+ }
+ }).show();
+ } else {
+ finish();
+ }
+ }
+
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
+ switch (requestCode) {
+ case REQUEST_PERMISSION_KEY: {
+ if ((grantResults.length > 0) && (grantResults[0] + grantResults[1]) == PackageManager.PERMISSION_GRANTED) {
+ Toast.makeText(this, "Screen Cast Permission Granted", Toast.LENGTH_SHORT).show();
+
+ } else {
+ isRecording = false;
+ toggleButton.setChecked(false);
+ Snackbar.make(findViewById(android.R.id.content), "Please enable Microphone and Storage permissions.",
+ Snackbar.LENGTH_INDEFINITE).setAction("ENABLE",
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent();
+ intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.setData(Uri.parse("package:" + getPackageName()));
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+ intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+ startActivity(intent);
+ }
+ }).show();
+ }
+ return;
+ }
+ }
}
}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 84f1951..eddd65d 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,18 +1,33 @@
-
-
-
\ No newline at end of file
+
+
+
+
+
+
+
\ No newline at end of file