Имитация фотосъемки в системном приложении камеры по умолчанию

Я делаю приложение голосового помощника для Android... которое запускает службу в фоновом режиме для распознавания голосовой команды. я хочу сделать снимок в системном приложении камеры по умолчанию, когда пользователь произносит слово «селфи». Я уже знаю, как работать с голосовой командой, но проблема в том, что я не могу заставить приложение камеры сделать снимок ...

я как-то пробовал но не помогло

1-й я попытался смоделировать событие ключа камеры 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);

это одна открытая камера, но она не будет снимать в телефоне без физического ключа камеры

2-й я попытался ввести ключевое событие «войти» ... например, дистанционный затвор Bluetooth ...

    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 проблемами: 1-й этот код нельзя использовать в сервисе 2-й невозможно внедрить событие в другое приложение, так как это может сделать только системное приложение

теперь вопрос как решить эту проблему? это возможно или нет? я кое-что читал в Интернете, что appium может это сделать, но он онлайн, и я хочу, чтобы мое приложение работало в автономном режиме

Обратите внимание, что: добавление разрешения камеры и разрешения на ввод событий не поможет, и я не хочу использовать API-интерфейс камеры, потому что я хочу сделать снимок в системном приложении камеры по умолчанию.


person m.r.davari    schedule 20.09.2016    source источник


Ответы (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 для более подробной информации о пакете. noreferrer">Служба специальных возможностей

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

Я загрузил рабочий пример -> https://github.com/ycrathi/cameraautoclick

Примечание. В приведенном выше репозитории GitHub есть несколько нежелательных кодов, которые я пробовал.

Это решение не является глобальным для всех приложений. Вы можете найти какое-нибудь известное приложение, такое как google camera, найти текст, а затем выполнить действие с пакетом кликов.

person Yogesh Rathi    schedule 27.11.2018

вы можете использовать сторонние приложения для «поддельных камер», такие как:

Поддельная камера Image2Camera от New Horizon Apps Поддельная камера — версия для пожертвований от Вацлава Балака

в качестве альтернативы вы можете использовать:

Эмулятор ICS - который поддерживает камеру

в качестве альтернативы вы можете использовать:

В дополнительных настройках AVD вы должны иметь возможность установить переднюю и заднюю камеры на веб-камеру () или эмуляцию.

person Chief Madog    schedule 20.09.2016
comment
спасибо за ответ ... но это не то, что я хочу, пожалуйста, прочитайте пост еще раз - person m.r.davari; 20.09.2016