如何使用 MediaProjection API 从后台服务类中截取屏幕截图?

2023-12-06

在对这个主题进行了大量研究之后,虽然我找到了一些答案,但我无法理解 MediaProjection API 的工作原理。

我想从后台服务类中截取设备的屏幕截图。是否可以做到呢。我有一个 MainActivity.java,它启动另一个服务类(而不是活动)的 serviceIntent。所以我想在这个服务类中实现这个API。请帮我


这是实现这一目标的棘手方法。

首先,您需要创建透明背景主题,例如。

    <style name="transparentTheme" parent="Theme.AppCompat.NoActionBar">
        <item name="android:background">#00000000</item> <!-- Or any transparency or color you need -->
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowBackground">@android:color/transparent</item>
        <item name="android:colorBackgroundCacheHint">@null</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowAnimationStyle">@android:style/Animation</item>
        <item name="android:navigationBarColor" tools:ignore="NewApi">#00000000</item>
        <item name="android:statusBarColor" tools:ignore="NewApi">#00000000</item>
    </style>

现在您需要在 Manifest 文件中的 ScreenShotActivity 上添加此应用此主题。

  <activity
            android:name=".Activities.ScreenShotActivity"
            android:theme="@style/transparentTheme" />
        <activity

您的 ScreenShotActivity 类。

public class ScreenShotActivity extends Activity {

    private static final int videoTime = 5000;
    private static final int REQUEST_CODE = 1000;
    private static final int REQUEST_PERMISSION = 1000;
    private static final SparseIntArray ORIENTATION = new SparseIntArray();
    private MediaProjectionManager mediaProjectionManager;
    private MediaProjection mediaProjection;
    private VirtualDisplay virtualDisplay;
    private ScreenShotActivity.MediaProjectionCallback mediaProjectionCallback;
    private MediaRecorder mediaRecorder;
    PostWebAPIData postWebAPIData;
    private int mScreenDensity;
    private static int DISPLAY_WIDTH = 720;
    private static int DISPLAY_HEIGHT = 1280;

    static {
        ORIENTATION.append(Surface.ROTATION_0, 90);
        ORIENTATION.append(Surface.ROTATION_90, 0);
        ORIENTATION.append(Surface.ROTATION_180, 270);
        ORIENTATION.append(Surface.ROTATION_270, 180);
    }

    private String screenShotUri = "";

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_screen_shot);
        init();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void init() {
        //Screen tracking Code Started here..............................
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        mScreenDensity = metrics.densityDpi;
        postWebAPIData = new PostWebAPIData();
        DISPLAY_HEIGHT = metrics.heightPixels;
        DISPLAY_WIDTH = metrics.widthPixels;

        mediaRecorder = new MediaRecorder();
        mediaProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
        if (ContextCompat.checkSelfPermission(ScreenShotActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                + ContextCompat.checkSelfPermission(ScreenShotActivity.this, Manifest.permission.RECORD_AUDIO)
                != PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(ScreenShotActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) ||
                    ActivityCompat.shouldShowRequestPermissionRationale(ScreenShotActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            } else {
                ActivityCompat.requestPermissions(ScreenShotActivity.this, new String[]{
                        Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        Manifest.permission.RECORD_AUDIO
                }, REQUEST_PERMISSION);
            }
        } else {
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    toogleScreenShare();
                }
            }, 500);
        }
    }


    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void toogleScreenShare() {
        initRecorder();
        recordScreen();
    }


    public void getPathScreenShot(String filePath) {
        FFmpegMediaMetadataRetriever med = new FFmpegMediaMetadataRetriever();

        med.setDataSource(filePath);
        Bitmap bmp = med.getFrameAtTime(2 * 1000000, FFmpegMediaMetadataRetriever.OPTION_CLOSEST);
        String myPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + new StringBuilder("/screenshot").append(".bmp").toString();

        File myDir = new File(myPath);
        myDir.mkdirs();
        Random generator = new Random();
        int n = 10000;
        n = generator.nextInt(n);
        String fname = "Image-" + n + ".jpg";
        File file = new File(myDir, fname);
        Log.i(TAG, "" + myDir);
        if (myDir.exists())
            myDir.delete();
        try {
            FileOutputStream out = new FileOutputStream(myDir);
            bmp.compress(Bitmap.CompressFormat.JPEG, 90, out);
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        postScreenShot(myPath);
    }

   
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void recordScreen() {
        if (mediaProjection == null) {
            startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);
        } else {
            virtualDisplay = createVirtualDisplay();
            mediaRecorder.start();
            onBackPressed();
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    mediaRecorder.stop();
                    mediaRecorder.reset();
                    stopRecordScreen();
                    destroyMediaProjection();
                    new Handler().postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            getPathScreenShot(screenShotUri);
                        }
                    }, 2000);
                }
            }, videoTime);
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private VirtualDisplay createVirtualDisplay() {
        return mediaProjection.createVirtualDisplay("MainActivity", DISPLAY_WIDTH, DISPLAY_HEIGHT, mScreenDensity, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                mediaRecorder.getSurface(), null, null);
    }

    private void initRecorder() {
        try {
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
            mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);

            screenShotUri = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) + new StringBuilder("/screenshot").append(".mp4").toString();

            mediaRecorder.setOutputFile(screenShotUri);
            mediaRecorder.setVideoSize(DISPLAY_WIDTH, DISPLAY_HEIGHT);
            mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
            mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            mediaRecorder.setVideoEncodingBitRate(512 * 1000);
            mediaRecorder.setVideoFrameRate(5);

            int rotation = getWindowManager().getDefaultDisplay().getRotation();
            int orientation = ORIENTATION.get(rotation + 90);
            mediaRecorder.setOrientationHint(orientation);
            mediaRecorder.prepare();
        } catch (IOException e) {
            e.printStackTrace();
            Log.d("ExceptionOccured", "" + e.getMessage());
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode != REQUEST_CODE) {
            stopService(new Intent(this, BackgroundService.class));
            startService(new Intent(this, BackgroundService.class));
            Toast.makeText(ScreenShotActivity.this, "Unknown Error", Toast.LENGTH_SHORT).show();
            Log.d("Livetracking", "ScreenShot" + requestCode + "  " + resultCode + " " + data);
            return;
        }
        if (resultCode != RESULT_OK) {
            stopService(new Intent(this, BackgroundService.class));
            startService(new Intent(this, BackgroundService.class));
            Toast.makeText(ScreenShotActivity.this, "Permission denied" + requestCode, Toast.LENGTH_SHORT).show();
            Log.d("Livetracking", "Screenshot" + requestCode + "  " + resultCode + " " + data);
            return;
        }
        Log.d("Livetracking", "Screenshot" + requestCode + "  " + resultCode + " " + data);

        mediaProjectionCallback = new ScreenShotActivity.MediaProjectionCallback();
        mediaProjection = mediaProjectionManager.getMediaProjection(resultCode, data);
        mediaProjection.registerCallback(mediaProjectionCallback, null);
        virtualDisplay = createVirtualDisplay();
        mediaRecorder.start();
        onBackPressed();
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                mediaRecorder.stop();
                mediaRecorder.reset();
                stopRecordScreen();
                destroyMediaProjection();
                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        getPathScreenShot(screenShotUri);
                    }
                }, 2000);
            }
        }, videoTime);
        ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        if (am != null) {
            List<ActivityManager.AppTask> tasks = am.getAppTasks();
            if (tasks != null && tasks.size() > 0) {
                Log.d("RemovingApp", "recent");
                tasks.get(0).setExcludeFromRecents(true);
            }
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private class MediaProjectionCallback extends MediaProjection.Callback {
        @Override
        public void onStop() {
            mediaRecorder.stop();
            mediaRecorder.reset();
            mediaProjection = null;
            stopRecordScreen();
            destroyMediaProjection();
            if (mediaProjection != null) {
                destroyMediaProjection();
            }
            super.onStop();
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void stopRecordScreen() {
        if (virtualDisplay == null) {
            virtualDisplay.release();
            if (mediaProjection != null) {
                destroyMediaProjection();
            }
            return;

        }
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private void destroyMediaProjection() {
        if (mediaProjection != null) {
            mediaProjection.unregisterCallback(mediaProjectionCallback);
            mediaProjection.stop();
            mediaProjection = null;
        }
    }
}

将这些权限添加到您的清单文件中。

   <uses-permission android:name="android.permission.RECORD_AUDIO" />
   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
   <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

现在魔法从这里开始,您需要像这样从服务中调用 ScreenShot Activity。

      Intent dialogIntent = new Intent(BackgroundService.this, ScreenShotActivity.class);
      dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      startActivity(dialogIntent);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 MediaProjection API 从后台服务类中截取屏幕截图? 的相关文章

随机推荐

  • 使用 LinkTo Predicate 的 TPL 数据流块

    我有一些块最终从 TransformBlock 变为基于 LinkTo 谓词的其他三个转换块之一 我正在使用 DataflowLinkOptions 来传播完成结果 问题是 当谓词满足并且该块启动时 我的管道的其余部分将继续 看起来管道应该
  • 在 Facebook 帖子中标记人物?

    如果您在 facebook com 上输入状态时按 则可以输入朋友的姓名并将其标记在您的 Facebook 状态中 使用 facebook connect 发布墙贴时如何标记朋友 目前无法像用户一样通过 API 来标记其他用户或页面 有趣的
  • SQL EXISTS 语句如何工作?

    我正在尝试学习 SQL 但很难理解 EXISTS 语句 我看到这句话关于 存在 但不明白 使用存在运算符 子查询可以返回零行 一行或多行 并且条件仅检查子查询是否返回任何行 如果您查看子查询的 select 子句 您会发现它由单个文字 1
  • 编辑清单以启用 availableToOtherTenants 后出现 Azure AD 错误

    我们正在尝试将 Web 应用程序和 Web API 部署到与我们的公司 Azure AD 帐户关联的新 Azure 订阅 但是 当我们尝试修改 Azure AD 清单以启用多租户标志 availableToOtherTenants 并在 W
  • 将经常使用的字段分配给局部变量是否更有效?

    我正在读source of java util HashMap并注意到它几乎总是分配table如果该值在方法中多次使用 则将字段转换为局部变量 既然这个类被记录为不是线程安全的并且该字段不是易失性的 那么这有什么意义呢 它会使代码更加高效吗
  • 使用 SDK 4.2 开发的 iPhone 应用程序,需要向后兼容 iOS 3.1.3 ..简单的方法吗?

    我已经使用 SDK 4 2 构建了一个 iPhone 应用程序 但我知道还想让它与 iOS 3 1 3 兼容 第一步是将部署目标设置为 3 1 3 它在 3 2 模拟器上运行良好 但应用程序有时会崩溃 因为我使用了一些早期 SDK 中不可用
  • 寻求R函数来融化5维数组,例如pivot_longer

    我有一个程序 它使用 reshape2 的熔化函数将具有命名和标记尺寸的 5 维数组熔化为长格式数据框 根据定义 该数据框只有二维 输入数组的每个维度对应于输出数据帧中的一列 并且还有一列保存存储在 5D 数组中的值 我知道 reshape
  • jQuery 菜单 - 基于 URL 的活动状态

    我只是想将活动状态改造为静态 html 菜单 菜单具有以下结构 div ul id MenuBar1 class MenuBarHorizontal gt li a href index htm Home a li li a href ab
  • 如何在 Google Chrome 版本 38 上禁用打印预览?

    我使用网络浏览器开发 POS 但是当我使用 onload window print 时出现打印预览 您需要按确定才能继续打印 其他来源建议在快捷方式上添加 disable print preview 这些似乎适用于旧版本 此扩展适用于什么版
  • 修复了页脚不显示最底部列表项的问题

    这是我的 XML 布局
  • 运行spring boot应用程序时proxyBeanMethods注释错误

    我正在尝试运行我的第一个 Spring Boot 应用程序 但面临一些问题 在我的应用程序文件中 这是我的代码 package com clog ServiceMgmt import java util List import org sp
  • 如何使用 kprobe 统计 Linux 内核中的 malloc 数量

    我想数一下mallocFedora 中使用 Kprobe 进行系统调用 我知道malloc不是系统调用 是在用户空间中实现的 但如果可能的话 我想用 kprobe 来计算 malloc 我必须为 Kprobe 提供的系统调用的名称是什么 例
  • openpyxl:将数据附加到第一个空列单元格

    背景 我有一个 Excel 工作簿 其中包含分布在各个工作表中的元数据 我需要从各个工作表中获取相关的数据列 并将它们合并到一个工作表中 使用以下代码 我已经能够创建一个新的工作表并向其中添加数据 Open workbook and ass
  • Eclipse 中的 Java Applet 窗口大小

    我试图将小程序窗口的大小设置为 500 x 500 但我无法实现这一点 这是我的代码 public void init Start Screen Color setBackground Color RED this setSize new
  • ORMLite:内部 DAO 对象为空

    我正在使用 ORMLite 尝试使用foreignCollectionKey 但出现以下错误 内部 DAO 对象为空 如果 LazyCollections 已被反序列化 则无法使用它们 我的对象名为 Zone public class Zo
  • 有没有其他方法可以实现没有无限 while 循环的“监听”功能?

    我一直在思考像 React 这样的代码和库 它们会在事件发生时自动做出反应 并且想知道所有这些都是如何在较低级别的 C 和机器代码中实现的 我似乎无法找出任何其他方式可以使用 if 不使用在另一个线程上运行的 while 循环来实现事件侦听
  • 将 WPF UserControl 中的内容绑定到其属性的不同方法有哪些优点/缺点?

    当开始使用 WPF UserControls 时 我偶然发现了几种将 UserControl 的内容绑定到其属性之一的方法 下面是我的控件的 C 代码示例 public sealed partial class MyUserControl
  • 升级到 Android Studio 2.3 后无法构建任何项目

    我在 Linux 上使用 Android Studio 今天我已经将其更新为version 2 3稳定 但现在我无法构建任何项目 甚至无法创建新项目 没有错误消息 只是构建进度无限时间有效 Edit 1 我还更新了 Gradle 插件2 1
  • JTable 渲染 JPanel

    我有一个专栏JTable我设置了一个自定义TableCellRenderer返回一个自定义的JPanel in its getTableCellRendererComponent method 习俗JPanel包含几个JTextField
  • 如何使用 MediaProjection API 从后台服务类中截取屏幕截图?

    在对这个主题进行了大量研究之后 虽然我找到了一些答案 但我无法理解 MediaProjection API 的工作原理 我想从后台服务类中截取设备的屏幕截图 是否可以做到呢 我有一个 MainActivity java 它启动另一个服务类