├── .github └── workflows │ └── android.yml ├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── androidyuan │ │ └── androidscreenshot_sysapi │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── androidyuan │ │ │ └── androidscreenshot_sysapi │ │ │ └── ExampleActivity.java │ └── res │ │ ├── layout │ │ └── activity_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── androidyuan │ └── androidscreenshot_sysapi │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── libshot ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── androidyuan │ │ └── lib │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── androidyuan │ │ │ └── lib │ │ │ └── screenshot │ │ │ ├── ScreenShotActivity.java │ │ │ └── Shooter.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── androidyuan │ └── lib │ └── ExampleUnitTest.java └── settings.gradle /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | # if gitlab action running occur a error such as 'No toolchains found in the NDK toolchains folder 2 | # for ABI with prefix: mips64el-linux-android', might you need to change 'distributionUrl' of gradle zip and 'classpath'. 3 | 4 | name: Build & Publish Debug APK 5 | 6 | on: 7 | push: 8 | branches: 9 | - master 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: set up JDK 1.8 17 | uses: actions/setup-java@v1 18 | with: 19 | java-version: 1.8 20 | - name: Make Gradle executable 21 | run: chmod +x ./gradlew 22 | - name: Build with Gradle 23 | run: ./gradlew build 24 | - name: Build Debug APK 25 | run: ./gradlew assembleDebug 26 | # - name: Releasing using Hub 27 | # uses: ShaunLWM/action-release-debugapk@master # this value is not any user,it is a pedestal, 28 | # env: 29 | # GITHUB_TOKEN: ${{ secrets.TOKEN }} 30 | # APP_FOLDER: app 31 | # RELEASE_TITLE: New Build 32 | 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | ### Android template 10 | # Built application files 11 | *.apk 12 | *.ap_ 13 | 14 | # Files for the ART/Dalvik VM 15 | *.dex 16 | 17 | # Java class files 18 | *.class 19 | 20 | # Generated files 21 | bin/ 22 | gen/ 23 | out/ 24 | 25 | # Gradle files 26 | .gradle/ 27 | build/ 28 | 29 | # Local configuration file (sdk path, etc) 30 | local.properties 31 | 32 | # Proguard folder generated by Eclipse 33 | proguard/ 34 | 35 | # Log Files 36 | *.log 37 | 38 | # Android Studio Navigation editor temp files 39 | .navigation/ 40 | 41 | # Android Studio captures folder 42 | captures/ 43 | 44 | # Intellij 45 | *.iml 46 | .idea/workspace.xml 47 | .idea/ 48 | 49 | # Keystore files 50 | *.jks 51 | 52 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AndroidScreenShot_SysApi 2 | 这是一个例子,以非常优雅的方案实现屏幕截图。 实现原理为 利用android 5.0 之后的录屏API获取一帧画面,来实现截屏。 3 | 4 | ## Special Features 5 | 6 | 1. 打破老旧的截屏方案,不能截状态栏的问题。 7 | 8 | 2. 截图其他app. 9 | 10 | ## Usage 11 | 12 | **使用Shotter** 13 | 14 | 请查阅代码 onClickReqPermission() 15 | 16 | **使用ScreenShotActivity** 17 | 18 | 请查阅代码 onClickShot(),该方法可以截图其他app 19 | 20 | 21 | ### 更多拓展: 22 | 23 | > 因为ScreenShotActivity是一个透明并隐藏的activity,玩法有很多: 24 | 25 | a. 截图桌面; 26 | 27 | b. 对其他app进行截图:你自己试着调整shotter的delay时间为3秒,然后start截图,再切换到其他app里,等toast截图成功。 28 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion '25.0.0' 6 | 7 | defaultConfig { 8 | applicationId "com.androidyuan.androidscreenshot_sysapi" 9 | minSdkVersion 15 10 | targetSdkVersion 25 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | 15 | lintOptions { 16 | abortOnError false 17 | } 18 | 19 | buildTypes { 20 | release { 21 | minifyEnabled false 22 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 23 | } 24 | debug{ 25 | minifyEnabled false 26 | } 27 | } 28 | } 29 | 30 | dependencies { 31 | compile fileTree(dir: 'libs', include: ['*.jar']) 32 | compile project(':libshot') 33 | testCompile 'junit:junit:4.12' 34 | compile 'com.android.support:appcompat-v7:25.0.1' 35 | } 36 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /home/wei/文档/tools/android-sdk-linux/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/androidyuan/androidscreenshot_sysapi/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.androidyuan.androidscreenshot_sysapi; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/androidyuan/androidscreenshot_sysapi/ExampleActivity.java: -------------------------------------------------------------------------------- 1 | package com.androidyuan.androidscreenshot_sysapi; 2 | 3 | import android.content.Intent; 4 | import android.media.projection.MediaProjectionManager; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.os.SystemClock; 8 | import android.support.annotation.RequiresApi; 9 | import android.support.v7.app.AppCompatActivity; 10 | import android.view.View; 11 | import android.widget.Toast; 12 | 13 | import com.androidyuan.lib.screenshot.ScreenShotActivity; 14 | import com.androidyuan.lib.screenshot.Shooter; 15 | 16 | /** 17 | * This class is a demo to show you how to use Shooter. 18 | */ 19 | public class ExampleActivity extends AppCompatActivity { 20 | 21 | private static final int REQ_CODE_PER = 0x2304; 22 | private static final int REQ_CODE_ACT = 0x2305; 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_main); 28 | } 29 | 30 | /** 31 | * This is an example for using Shooter. 32 | * This method will request permission and take screenshot on this Activity. 33 | */ 34 | public void onClickReqPermission(View view) { 35 | if (Build.VERSION.SDK_INT >= 21) { 36 | startActivityForResult(createScreenCaptureIntent(), REQ_CODE_PER); 37 | } 38 | } 39 | 40 | /** 41 | * using {@see ScreenShotActivity} to take screenshot on current Activity directly. 42 | * If you press home it will take screenshot on another app. 43 | * @param view 44 | */ 45 | public void onClickShot(View view) { 46 | startActivityForResult(ScreenShotActivity.createIntent(this, null,0), REQ_CODE_ACT); 47 | toast("Press home key,open another app.");//if you want to take screenshot on another app. 48 | } 49 | 50 | 51 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 52 | private Intent createScreenCaptureIntent() { 53 | //Here using media_projection instead of Context.MEDIA_PROJECTION_SERVICE to make it successfully build on low api. 54 | return ((MediaProjectionManager) getSystemService("media_projection")).createScreenCaptureIntent(); 55 | } 56 | 57 | private String getSavedPath() { 58 | return getExternalFilesDir("screenshot").getAbsoluteFile() + "/" 59 | + SystemClock.currentThreadTimeMillis() + ".png"; 60 | } 61 | 62 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 63 | super.onActivityResult(requestCode, resultCode, data); 64 | switch (requestCode) { 65 | 66 | case REQ_CODE_ACT: { 67 | if (resultCode == RESULT_OK && data != null) { 68 | toast("Screenshot saved at " + data.getData().toString()); 69 | } 70 | else{ 71 | toast("You got wrong."); 72 | } 73 | } 74 | break; 75 | case REQ_CODE_PER: { 76 | if (resultCode == RESULT_OK && data != null) { 77 | Shooter shooter = new Shooter(ExampleActivity.this, resultCode, data); 78 | shooter.startScreenShot(getSavedPath(), new Shooter.OnShotListener() { 79 | @Override 80 | public void onFinish(String path) { 81 | //here is done status. 82 | toast("Screenshot saved at " + path); 83 | } 84 | 85 | @Override 86 | public void onError() { 87 | toast("You got wrong."); 88 | } 89 | } 90 | ); 91 | } else if (resultCode == RESULT_CANCELED) { 92 | //user canceled. 93 | } else { 94 | 95 | } 96 | } 97 | } 98 | } 99 | 100 | 101 | private void toast(String str) { 102 | Toast.makeText(ExampleActivity.this, str, Toast.LENGTH_LONG).show(); 103 | } 104 | 105 | private void goBackground() { 106 | Intent startMain = new Intent(Intent.ACTION_MAIN); 107 | startMain.addCategory(Intent.CATEGORY_HOME); 108 | startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 109 | startActivity(startMain); 110 | } 111 | 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 |