【问题标题】:Simulate taking picture in default system camera app在默认系统相机应用中模拟拍照
【发布时间】:2016-09-20 14:38:02
【问题描述】:

我正在制作 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,因为我想在默认系统相机应用程序中拍照。

【问题讨论】:

    标签: android camera keyevent keycode


    【解决方案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()返回所有可点击的文本按钮,谷歌默认应用程序有Take Photo文本所以对于这个视图你可以执行操作。

    为每 10 秒捕获一次图片添加了 处理程序,以便更清楚地说明。

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

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

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

    注意:在上面的 GitHub repo 中有多个不需要的代码,我试过了。

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

    【讨论】:

      【解决方案2】:

      您可以使用 3rd 方“假相机”应用,例如:

      Image2Camera New Horizo​​​​n Apps的假相机 假相机 - Vaclav Balak 捐赠版本

      您也可以使用:

      ICS 模拟器 - 支持相机

      您也可以使用:

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

      【讨论】:

      • 感谢您的回答...但这不是我想要的,请再次阅读帖子
      猜你喜欢
      • 2011-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多