From a2484f33baad80914b764adc0c656f49a5bb3cb0 Mon Sep 17 00:00:00 2001 From: hanweiming Date: Wed, 5 Sep 2018 09:14:35 +0800 Subject: [PATCH] Initial commit --- .gitignore | 10 + .idea/caches/build_file_checksums.ser | Bin 0 -> 545 bytes .idea/codeStyles/Project.xml | 29 +++ .idea/gradle.xml | 18 ++ .idea/misc.xml | 34 ++++ .idea/runConfigurations.xml | 12 ++ app/.gitignore | 1 + app/build.gradle | 28 +++ app/proguard-rules.pro | 21 +++ .../screencap/ExampleInstrumentedTest.java | 26 +++ app/src/main/AndroidManifest.xml | 34 ++++ .../administrator/screencap/MainActivity.java | 119 ++++++++++++ .../screencap/RecordApplication.java | 29 +++ .../screencap/RecordService.java | 169 +++++++++++++++++ .../drawable-v24/ic_launcher_foreground.xml | 34 ++++ .../res/drawable/ic_launcher_background.xml | 170 +++++++++++++++++ app/src/main/res/layout/activity_main.xml | 27 +++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3056 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 5024 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2096 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2858 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4569 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 7098 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6464 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10676 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9250 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15523 bytes app/src/main/res/values/colors.xml | 6 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/styles.xml | 11 ++ .../screencap/ExampleUnitTest.java | 17 ++ build.gradle | 27 +++ gradle.properties | 13 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54708 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 172 ++++++++++++++++++ gradlew.bat | 84 +++++++++ settings.gradle | 1 + 40 files changed, 1111 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/caches/build_file_checksums.ser create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/com/example/administrator/screencap/ExampleInstrumentedTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/com/example/administrator/screencap/MainActivity.java create mode 100644 app/src/main/java/com/example/administrator/screencap/RecordApplication.java create mode 100644 app/src/main/java/com/example/administrator/screencap/RecordService.java create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/test/java/com/example/administrator/screencap/ExampleUnitTest.java create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5edb4ee --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +*.iml +.gradle +/local.properties +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +.DS_Store +/build +/captures +.externalNativeBuild diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser new file mode 100644 index 0000000000000000000000000000000000000000..6ad01aec11a9e0615d83d1adbec07fe0785fb2a9 GIT binary patch literal 545 zcmZ4UmVvdnh`~NNKUXg?FQq6yGexf?KR>5fFEb@IQ7^qHF(oHeub?PDD>b=9F91S2 zm1gFoxMk*~I%lLNXBU^|7Q2L-Ts|(GuF1r}uGBYr_F>vMNC#JY1CYR(Fc`|U8WE7AhoC@Gqt!BuDJ2(tb0-VzTCO5tbL{`b005ZFmSet2`x@7 zDvohX$<55mEG{WZ1bR9K>Yx}zJYg7iMYiW=Kf@-LmkpdV-u!T?D`61Cqxy3%^Qt`w QOZ_(4rWrpwE09zH0LkRPpa1{> literal 0 HcmV?d00001 diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..30aa626 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..7ac24c7 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..c0f68ed --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..62bb6e4 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,28 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 28 + defaultConfig { + applicationId "com.example.administrator.screencap" + minSdkVersion 21 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'com.android.support:appcompat-v7:28.0.0-rc02' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/androidTest/java/com/example/administrator/screencap/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/administrator/screencap/ExampleInstrumentedTest.java new file mode 100644 index 0000000..d63763a --- /dev/null +++ b/app/src/androidTest/java/com/example/administrator/screencap/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package com.example.administrator.screencap; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.example.administrator.screencap", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..1643c7f --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/administrator/screencap/MainActivity.java b/app/src/main/java/com/example/administrator/screencap/MainActivity.java new file mode 100644 index 0000000..4195eb3 --- /dev/null +++ b/app/src/main/java/com/example/administrator/screencap/MainActivity.java @@ -0,0 +1,119 @@ +package com.example.administrator.screencap; + +import android.Manifest; +import android.content.ComponentName; +import android.content.Intent; +import android.content.ServiceConnection; +import android.content.pm.PackageManager; +import android.media.projection.MediaProjection; +import android.media.projection.MediaProjectionManager; +import android.os.IBinder; +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.view.View; +import android.widget.Button; +import android.widget.Toast; + + +public class MainActivity extends AppCompatActivity { + private static final int RECORD_REQUEST_CODE = 101; + private static final int STORAGE_REQUEST_CODE = 102; + private static final int AUDIO_REQUEST_CODE = 103; + + private MediaProjectionManager projectionManager; + private MediaProjection mediaProjection; + private RecordService recordService; + private Button startBtn; + + RecordApplication recordApplication; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + projectionManager = (MediaProjectionManager) getSystemService(MEDIA_PROJECTION_SERVICE); + setContentView(R.layout.activity_main); + +// recordApplication = RecordApplication.getInstance(); +// recordApplication.onCreate(); + startService(new Intent(this, RecordService.class)); + + startBtn = (Button) findViewById(R.id.screencap); +// startBtn.setEnabled(false); + startBtn.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + recordService = new RecordService(); + if (recordService.isRunning()) { + recordService.stopRecord(); + startBtn.setText("开始录屏"); + Toast.makeText(MainActivity.this,"视频录制完成,存放地址为\n"+ RecordService.getScreencapPath(),Toast.LENGTH_LONG).show(); + } else { + Intent captureIntent = projectionManager.createScreenCaptureIntent(); + startActivityForResult(captureIntent, RECORD_REQUEST_CODE); + } + } + }); + + if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, + new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, STORAGE_REQUEST_CODE); + } + + if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.RECORD_AUDIO) + != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(this, + new String[] {Manifest.permission.RECORD_AUDIO}, AUDIO_REQUEST_CODE); + } + + Intent intent = new Intent(this, RecordService.class); + bindService(intent, connection, BIND_AUTO_CREATE); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + unbindService(connection); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == RECORD_REQUEST_CODE && resultCode == RESULT_OK) { + mediaProjection = projectionManager.getMediaProjection(resultCode, data); + recordService.setMediaProject(mediaProjection); + if(startBtn.getText().toString().equals("开始录屏")){ + recordService.startRecord(); + startBtn.setText("停止录屏"); + } + } + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == STORAGE_REQUEST_CODE || requestCode == AUDIO_REQUEST_CODE) { + if (grantResults[0] != PackageManager.PERMISSION_GRANTED) { + finish(); + } + } + } + + private ServiceConnection connection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName className, IBinder service) { + DisplayMetrics metrics = new DisplayMetrics(); + getWindowManager().getDefaultDisplay().getMetrics(metrics); + RecordService.RecordBinder binder = (RecordService.RecordBinder) service; + recordService = binder.getRecordService(); + recordService.setConfig(metrics.widthPixels, metrics.heightPixels, metrics.densityDpi); + startBtn.setEnabled(true); + startBtn.setText(recordService.isRunning() ? "停止录屏" : "开始录屏"); + } + + @Override + public void onServiceDisconnected(ComponentName arg0) {} + }; +} diff --git a/app/src/main/java/com/example/administrator/screencap/RecordApplication.java b/app/src/main/java/com/example/administrator/screencap/RecordApplication.java new file mode 100644 index 0000000..7eaa93a --- /dev/null +++ b/app/src/main/java/com/example/administrator/screencap/RecordApplication.java @@ -0,0 +1,29 @@ +package com.example.administrator.screencap; + +import android.app.Application; +import android.content.Context; +import android.content.Intent; + + +public class RecordApplication extends Application { + + private static RecordApplication application; + + @Override + protected void attachBaseContext(Context base) { + super.attachBaseContext(base); + application = this; + } + + @Override + public void onCreate() { + super.onCreate(); + application = this; + // 启动 Marvel service + startService(new Intent(this, RecordService.class)); + } + + public static RecordApplication getInstance() { + return application; + } +} diff --git a/app/src/main/java/com/example/administrator/screencap/RecordService.java b/app/src/main/java/com/example/administrator/screencap/RecordService.java new file mode 100644 index 0000000..4c63cb5 --- /dev/null +++ b/app/src/main/java/com/example/administrator/screencap/RecordService.java @@ -0,0 +1,169 @@ +package com.example.administrator.screencap; + + +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.os.Binder; +import android.os.Environment; +import android.os.HandlerThread; +import android.os.IBinder; +import android.util.DisplayMetrics; +import android.util.Log; +import android.view.WindowManager; + +import java.io.File; +import java.io.IOException; + + +public class RecordService extends Service { + private static MediaProjection mediaProjection; + private static MediaRecorder mediaRecorder; + private static VirtualDisplay virtualDisplay; + + private static boolean running = false; + +// private int width = 720; +// private int height = 1080; +// private int dpi = 320; + + DisplayMetrics dm = RecordApplication.getInstance().getResources().getDisplayMetrics(); + private int width = dm.widthPixels; + private int height = dm.heightPixels; + private int dpi = dm.densityDpi; + + static String ScreencapPath; + static String videoName; + + + @Override + public IBinder onBind(Intent intent) { + // mediaRecorder = new MediaRecorder(); + return new RecordBinder(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return START_STICKY; + } + + + + @Override + public void onCreate() { + super.onCreate(); + HandlerThread serviceThread = new HandlerThread("service_thread", + android.os.Process.THREAD_PRIORITY_BACKGROUND); + serviceThread.start(); + // running = false; + // mediaRecorder = new MediaRecorder(); + } + + @Override + public void onDestroy() { + Log.i("AAAAA-------","onDestory"); + super.onDestroy(); + + } + + public void setMediaProject(MediaProjection project) { + mediaProjection = project; + // mediaRecorder = new MediaRecorder(); + } + + public boolean isRunning() { + return running; + } + + public void setConfig(int width, int height, int dpi) { + this.width = width; + this.height = height; + this.dpi = dpi; + } + + public boolean startRecord() { + if (mediaProjection == null || running) { + return false; + } + + initRecorder(); + createVirtualDisplay(); + // mediaRecorder.setOnInfoListener((MediaRecorder.OnInfoListener) getApplicationContext()); + // mediaRecorder.setOnErrorListener((MediaRecorder.OnErrorListener) getApplicationContext()); + mediaRecorder.start(); + running = true; + return true; + } + + public boolean stopRecord() { + if (!running) { + return false; + } + running = false; + mediaRecorder.stop(); + // mediaRecorder.reset(); + mediaRecorder.release(); + virtualDisplay.release(); + mediaProjection.stop(); + mediaRecorder = null; + + return true; + } + + private void createVirtualDisplay() { + virtualDisplay = mediaProjection.createVirtualDisplay("MainScreen", width, height, dpi, + DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, mediaRecorder.getSurface(), null, null); + } + + private void initRecorder() { + mediaRecorder = new MediaRecorder(); + mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); + mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE); + mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); + videoName = System.currentTimeMillis() + ".mp4"; + mediaRecorder.setOutputFile(getsaveDirectory() + videoName); + mediaRecorder.setVideoSize(width, height); + mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); + mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); + mediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024); + mediaRecorder.setVideoFrameRate(30); + try { + mediaRecorder.prepare(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static String getScreencapPath(){ + ScreencapPath = File.separator +"xinlv" + File.separator + "Screencap" + videoName; + return ScreencapPath; + } + + public String getsaveDirectory() { + if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { + String rootDir = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator +"xinlv" + File.separator + "Screencap" + File.separator;//getAbsolutePath() + File file = new File(rootDir); + if (!file.exists()) { + if (!file.mkdirs()) { + return null; + } + } + + // Toast.makeText(getBaseContext(), rootDir, Toast.LENGTH_SHORT).show(); + + return rootDir; + } else { + return null; + } + } + + public class RecordBinder extends Binder { + public RecordService getRecordService() { + return RecordService.this; + } + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..c7bd21d --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..d5fccc5 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..fb097e3 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,27 @@ + + + +