7

我的用户将使用启用 TalkBack 或其他一些无障碍服务。我想在我们的应用程序中捕获 onKeyEvent 事件,但该事件被分派到启用的辅助功能服务。我创建了以下基本的无障碍服务。

public class Accessibility_Service extends AccessibilityService {

    private String TAG = Accessibility_Service.class.getSimpleName();

    @Override
    public boolean onKeyEvent(KeyEvent event) {
        int action = event.getAction();
        int keyCode = event.getKeyCode();
        if (action == KeyEvent.ACTION_UP) {
            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
                Log.d("Hello", "KeyUp");
            } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
                Log.d("Hello", "KeyDown");
            }
            return true;
        } else {
            return super.onKeyEvent(event);
        }
    }

    /**
     * Passes information to AccessibilityServiceInfo.
     */
    @Override
    public void onServiceConnected() {
        Log.v(TAG, "on Service Connected");
        AccessibilityServiceInfo info = new AccessibilityServiceInfo();
        info.packageNames = new String[] { "com.camacc" };
        info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
        info.notificationTimeout = 100;
        info.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN;
        setServiceInfo(info);

    }// end onServiceConnected

    /**
     * Called on an interrupt.
     */
    @Override
    public void onInterrupt() {
        Log.v(TAG, "***** onInterrupt");

    }// end onInterrupt

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        // TODO Auto-generated method stub

    }
}// end Accessibility_Service class

当我检查 logcat 时,我没有得到任何回应。是否可以在 TalkBack 或其他此类辅助功能服务之前使用音量调低和调高事件?

谢谢你。

编辑:

添加了以下标志仍然没有运气:

info.flags = AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS;
4

5 回答 5

9

尝试在 xml 资源中像这样配置辅助功能服务,如果您需要更多信息,请查看:https ://developer.android.com/guide/topics/ui/accessibility/services.html

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeContextClicked|typeViewClicked"
android:packageNames="com.example.andres.eventcapture"
android:accessibilityFlags="flagRequestFilterKeyEvents"
android:accessibilityFeedbackType="feedbackAllMask"
android:notificationTimeout="50"
android:canRetrieveWindowContent="true"
android:settingsActivity=""
android:canRequestFilterKeyEvents="true"
/>

效果很好!

于 2016-06-17T09:05:57.333 回答
4

老问题,但也许这个答案会对某人有所帮助。

是的,另一个无障碍服务可能会使用 KeyEvent。

请查看FLAG_REQUEST_FILTER_KEY_EVENTS文档,有: 设置此标志并不能保证此服务将过滤关键事件,因为在任何给定时间只有一个服务可以这样做。这避免了在启用不同密钥过滤服务的情况下由于行为变化而引起的用户混淆。如果已经启用了另一个密钥过滤服务,则此服务将不会接收密钥事件。

所以另一个无障碍服务可以使用 KeyEvents。

于 2015-08-31T17:10:03.340 回答
2

尝试删除 info.packageNames 或将其设置为 null。根据此处的文档,您只会收到这些应用程序包生成的事件。

于 2016-09-29T12:47:49.077 回答
0

如果您特别希望从服务中按下音量键,这将起作用。它将覆盖音量键操作,因此请避免全局使用它。

public class VolumeKeyController {

    private MediaSessionCompat mMediaSession;
    private final Context mContext;

    public VolumeKeyController(Context context) {
        mContext = context;
    }

    private void createMediaSession() {
        mMediaSession = new MediaSessionCompat(mContext, KeyUtil.log);

        mMediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
                MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
        mMediaSession.setPlaybackState(new Builder()
                .setState(PlaybackStateCompat.STATE_PLAYING, 0, 0)
                .build());
        mMediaSession.setPlaybackToRemote(getVolumeProvider());
        mMediaSession.setActive(true);
    }

    private VolumeProviderCompat getVolumeProvider() {
        final AudioManager audio = mContext.getSystemService(Context.AUDIO_SERVICE);

        int STREAM_TYPE = AudioManager.STREAM_MUSIC;
        int currentVolume = audio.getStreamVolume(STREAM_TYPE);
        int maxVolume = audio.getStreamMaxVolume(STREAM_TYPE);
        final int VOLUME_UP = 1;
        final int VOLUME_DOWN = -1;

        return new VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_RELATIVE, maxVolume, currentVolume) {
            @Override
            public void onAdjustVolume(int direction) {
                // Up = 1, Down = -1, Release = 0
                // Replace with your action, if you don't want to adjust system volume
                if (direction == VOLUME_UP) {
                    audio.adjustStreamVolume(STREAM_TYPE,
                            AudioManager.ADJUST_RAISE, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
                }
                else if (direction == VOLUME_DOWN) {
                    audio.adjustStreamVolume(STREAM_TYPE,
                            AudioManager.ADJUST_LOWER, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE);
                }
                setCurrentVolume(audio.getStreamVolume(STREAM_TYPE));
            }
        };
    }

    // Call when control needed, add a call to constructor if needed immediately
    public void setActive(boolean active) {
        if (mMediaSession != null) {
            mMediaSession.setActive(active);
            return;
        }
        createMediaSession();
    }

    // Call from Service's onDestroy method
    public void destroy() {
        if (mMediaSession != null) {
            mMediaSession.release();
        }
    }
}
于 2018-03-10T19:52:37.747 回答
-4

我认为您必须在扩展 AccessibilityService 时实现“onAccessibilityEvent()”方法;例如:

@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
    final int eventType = event.getEventType();
    switch(eventType) {
        case AccessibilityEvent.TYPE_VIEW_CLICKED:
            do somthing
            break;
        case AccessibilityEvent.TYPE_VIEW_FOCUSED:
            do somthing
            break;
    }
于 2014-09-19T03:03:28.167 回答