onKeyEvent & Accessibility Service
Мои пользователи будут использовать 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;
5 ответов
Попробуйте настроить Службу специальных возможностей, например, в ресурсе 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"
/>
Это сработало хорошо!
Старый вопрос, но, возможно, этот ответ кому-нибудь поможет.
Да, возможно, что другой сервис специальных возможностей использует KeyEvent.
Пожалуйста, ознакомьтесь с документацией FLAG_REQUEST_FILTER_KEY_EVENTS, там есть: Установка этого флага не гарантирует, что эта служба будет фильтровать ключевые события, так как только одна служба может сделать это в любой момент времени. Это позволяет избежать путаницы из-за изменения поведения в случае, если включены разные службы фильтрации ключей. Если уже включена другая служба фильтрации ключей, она не будет получать ключевые события.
Таким образом, другой сервис специальных возможностей может использовать KeyEvents.
Попробуйте удалить info.packageNames или установить для него значение null. Согласно документации здесь вы будете получать только события, сгенерированные этими пакетами приложений.
Если вы специально хотите нажимать клавиши регулировки громкости от службы, это будет работать. Он отменяет действие клавиши громкости, поэтому избегайте его использования глобально.
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();
}
}
}
Я думаю, что вы должны реализовать метод onAccessibilityEvent() при расширении AccessibilityService;
@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;
}