在默认系统相机应用中模拟拍照 [英] Simulate taking picture in default system camera app

查看:144
本文介绍了在默认系统相机应用中模拟拍照的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

im制作android语音助手应用程序...在后台运行服务以识别语音命令. 当用户说"selfie"一词时,我想在默认的系统相机应用程序中拍照.我已经知道如何使用语音命令,但问题是我无法使相机应用程序拍照...

im making android voice assistant app...that run service in background for recognizing the voice command . i want to take picture in default system camera app when the user say's the word "selfie".i already know how to work with voice command but the problem is i cant make the camera app take picture ...

我尝试了一些方法,但没有帮助

i tried some way but wont helped

第一次我尝试模拟android相机按键事件

1st i tried to simulate android camera key event

Intent intent1 = new Intent("android.intent.action.CAMERA_BUTTON");
intent1.putExtra("android.intent.extra.KEY_EVENT", new KeyEvent(0,
KeyEvent.KEYCODE_CAMERA));
sendOrderedBroadcast(intent1, null);
intent1 = new Intent("android.intent.action.CAMERA_BUTTON");
intent1.putExtra("android.intent.extra.KEY_EVENT", new KeyEvent(1,
KeyEvent.KEYCODE_CAMERA));
sendOrderedBroadcast(intent1, null);

这一个打开的摄像头,但是没有物理摄像头键就无法在手机中拍照

this one open camera but wont take picture in phone's without physical camera key

第二次,我试图注入按键事件"enter" ...像蓝牙遥控器一样...

2nd i tried to inject key event "enter" ... like bluetooth remote shutter ...

    KeyEvent eventDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER);
    KeyEvent eventUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER);
    dispatchKeyEvent(eventDown);
    dispatchKeyEvent(eventUp);

但是在此过程中,我遇到了2个问题:第一,该代码无法在服务中使用;第二,由于只有系统应用可以执行此操作,因此无法向其他应用注入事件

but in this one i faced 2 problem 1st this code cant be use in service 2nd its impossible to inject event to other app since that only system app could do this

现在的问题是如何解决此问题? 有没有可能? 我在网上阅读了一些appium可以做到的事情,但它的在线&我希望我的应用离线运行

now the question is how can i fix this problem? is it possible or not? i read some thing on web that appium could do this but its online & i want my app working off line

请注意:添加摄像头权限&注入事件权限将无济于事,我也不想使用camera api,因为我想在默认的系统camera应用中拍照.

note that : adding camera permission & inject event permission wont help and i don't want to use camera api because i want to take pic in default system camera app.

推荐答案

是的,可能经过2天的调查,我找到了解决方案.

Yes, Its possible After 2 days investigation I find the solution.

要求:打开系统相机应用程序,然后单击图片.

Requirement : Open system camera app and click pic.

第1步:

在清单文件中添加摄像机"权限:

Add Camera permission in manifest file:

<uses-permission android:name="android.permission.CAMERA"/>

<uses-feature
    android:name="android.hardware.camera"
    android:required="false" />
<uses-feature
    android:name="android.hardware.camera.front"
    android:required="false" />

步骤2:创建一项扩展 AccessibilityService

    <service
        android:name=".AccessTest"
        android:enabled="true"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
        android:exported="true">
        <intent-filter>
            <action android:name="android.accessibilityservice.AccessibilityService" />
        </intent-filter>

        <meta-data
            android:name="android.accessibilityservice"
            android:resource="@xml/accessibility_service_config"/>
    </service>

第3步:在需要时启动服务

    Intent mailAccessabilityIntent = new Intent(getApplicationContext(), AccessTest.class);
    startService(mailAccessabilityIntent);

第4步::添加可访问性文件.

Step 4: Add accessibility file.

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:accessibilityEventTypes="typeAllMask"
    android:accessibilityFeedbackType="feedbackAllMask"
    android:accessibilityFlags="flagEnableAccessibilityVolume"
    android:canRetrieveWindowContent="true"
    android:notificationTimeout="100"
    android:packageNames="com.google.android.GoogleCamera"
    android:settingsActivity="com.mobiliya.cameraautoclick.MainActivity" />

第5步:在要处理与摄像机相关的侦听器的地方编写服务类.

Step 5: Write service class where you want to handle camera related listener.

public class AccessTest extends AccessibilityService {

    private final static String TAG = "Yogesh";


    @Override
    public void onCreate() {
        super.onCreate();
        Log.d("Yogesh","I am started");
    }

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        Log.d(TAG, "onServiceConnected");
    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
      Log.d(TAG, "ACC::onAccessibilityEvent: " + event.getEventType());

        //TYPE_WINDOW_STATE_CHANGED == 32
        if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event
                .getEventType()) {
            AccessibilityNodeInfo nodeInfo = event.getSource();

            if (nodeInfo == null) {
                return;
            }


            Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

            String x = takePictureIntent.resolveActivity(getPackageManager()).getPackageName();

            Log.d("Yogesh","Package name " + x);

            List<AccessibilityNodeInfo> list1 = nodeInfo.findAccessibilityNodeInfosByText("Switch to front camera");

            for (AccessibilityNodeInfo node : list1) {
                Log.i(TAG, "ACC::onAccessibilityEvent: click " + node);
                node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }

            final List<AccessibilityNodeInfo> list = nodeInfo.findAccessibilityNodeInfosByText("Take photo");


            final android.os.Handler handler = new android.os.Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {

                    for (AccessibilityNodeInfo node : list) {
                        Log.i(TAG, "ACC::onAccessibilityEvent: click " + node);
                        node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
                    }
                    handler.postDelayed(this,5000);
                }
            },10000);

            for (AccessibilityNodeInfo node : list) {
                Log.i(TAG, "ACC::onAccessibilityEvent: click " + node);
                node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
            }

            Log.d(TAG,"Access " + getAllChildNodeText(nodeInfo).toString());
        }
    }



    private List<CharSequence> getAllChildNodeText(AccessibilityNodeInfo infoCompat) {
        List<CharSequence> contents = new ArrayList<>();
        if (infoCompat == null)
            return contents;
        if (infoCompat.getContentDescription() != null) {
            contents.add(infoCompat.getContentDescription().toString().isEmpty() ? "unlabelled" : infoCompat.getContentDescription());
        } else if (infoCompat.getText() != null) {
            contents.add(infoCompat.getText().toString().isEmpty() ? "unlabelled" : infoCompat.getText());
        } else {
            getTextInChildren(infoCompat, contents);
        }
        if (infoCompat.isClickable()) {
            if (infoCompat.getClassName().toString().contains(Button.class.getSimpleName())) {
                if (contents.size() == 0) {
                    contents.add("Unlabelled button");
                } else {
                    contents.add("button");
                }
            }
            contents.add("Double tap to activate");
        }
        return contents;
    }


    private void getTextInChildren(AccessibilityNodeInfo nodeInfoCompat, List<CharSequence> contents) {
        if (nodeInfoCompat == null)
            return;
        if (!nodeInfoCompat.isScrollable()) {
            if (nodeInfoCompat.getContentDescription() != null) {
                contents.add(nodeInfoCompat.getContentDescription());
            } else if (nodeInfoCompat.getText() != null) {
                contents.add(nodeInfoCompat.getText());
            }
            if (nodeInfoCompat.getChildCount() > 0) {
                for (int i = 0; i < nodeInfoCompat.getChildCount(); i++) {
                    if (nodeInfoCompat.getChild(i) != null) {
                        getTextInChildren(nodeInfoCompat.getChild(i), contents);
                    }
                }
            }
        }
    }



    @Override
    public void onInterrupt() {

    }
}

在此处 getAllChildNodeText()返回所有可单击的文本按钮,Google默认应用程序具有Take Photo文本,因此对于此视图您可以执行操作.

Here getAllChildNodeText() return all text button which is clickable, Google default application have Take Photo text so for this view you can perform action.

添加了处理程序,用于每10秒捕获一次图片,以进行更清晰的说明.

Added handler for capture pic every 10 seconds for more clarification.

如果您想跟踪多个相机应用程序,则删除以下行,并使用Java代码设置程序包的更多详细信息,请参见-无障碍服务

If you want to track multiple camera app then remove below line and use Java code for set package more details See -Accessibility Service

android:packageNames="com.google.android.GoogleCamera"

我上传了工作示例-> https://github.com/ycrathi/cameraautoclick

注意:在上面的GitHub存储库中,我尝试了多个不需要的代码.

此解决方案并非适用于所有应用程序.您可以找到一些著名的应用程序,例如 google camera ,并找到文本,然后明智地执行点击操作包.

This solution is not global for all app. You can find some famous app like google camera and find text and then perform click action package wise.

这篇关于在默认系统相机应用中模拟拍照的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆