在默认系统相机应用程序中模拟拍照

时间:2016-09-20 14:38:03

标签: android camera keyevent keycode

即时制作Android语音助手应用程序...在后台运行服务以识别语音命令。 当用户说出“自拍”这个词时,我想在默认的系统相机应用程序中拍照。我已经知道如何使用语音命令,但问题是我不能让相机应用拍照...

我试过某种方式,但不会帮助

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

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);
这是一款开放式摄像机,但在没有物理摄像头钥匙的情况下不会在手机中拍照

第二次我试着注入关键事件“进入”......就像蓝牙遥控快门......

    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个问题第一个这个代码不能用于服务第二个不可能将事件注入到其他应用程序,因为只有系统应用程序可以这样做

现在的问题是如何解决这个问题?  有可能吗? 我在网上读到一些内容,appium可以做到这一点,但它的在线&我希望我的应用程序脱机工作

请注意:添加相机权限&注入事件权限不会有帮助,我不想使用相机API,因为我想拍摄默认系统相机应用程序中的图片。

2 个答案:

答案 0 :(得分:1)

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

  

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

第1步:

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

<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步::添加可访问性文件。

<?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:在要处理与摄像机相关的侦听器的地方编写服务类。

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文本,因此对于此视图,您可以执行操作。

添加了处理程序,用于每10秒捕获一次图片,以进一步说明问题。

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

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

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

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

  
    

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

  

答案 1 :(得分:0)

你可以使用第三方&#34;假相机&#34;应用程序如:

Image2Camera 新Horizo​​n Apps假冒相机 假相机 - 由Vaclav Balak捐赠版本

或者您可以使用:

ICS模拟器 - 支持相机

或者您可以使用:

在AVD高级设置中,您应该能够将前置和后置摄像头设置为Webcam()或Emulated