I am following this official tutorial by Google, which shows adding a layout on top of a view. However, it adds the layout always, from the time accessibility service is activated.
I want to add this layout programmatically, after a certain action and remove it again, after some other action.
Here is my XML for accessibility service:
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
android:packageNames="com.whatsapp"
android:accessibilityFeedbackType="feedbackSpoken"
android:notificationTimeout="100"
android:settingsActivity="com.example.android.apis.accessibility.TestBackActivity"
android:canRetrieveWindowContent="true" />
Following is my code, which I have mostly borrowed from the tutorial:
public class GlobalActionBarService extends AccessibilityService {
private static final String TAG = "AccessibilityService";
private WindowManager mWindowManager;
FrameLayout mLayout;
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
final int eventType = event.getEventType();
String eventText = null;
switch(eventType) {
case AccessibilityEvent.TYPE_VIEW_CLICKED:
eventText = "Clicked: ";
break;
case AccessibilityEvent.TYPE_VIEW_FOCUSED:
eventText = "Focused: ";
break;
}
eventText = eventText + event.getContentDescription();
mLayout = new FrameLayout(this);
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
lp.format = PixelFormat.TRANSLUCENT;
lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.TOP;
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.action_bar, mLayout);
if (eventText.toLowerCase().contains("test")) {
Log.d(TAG, "Oh! Displaying the layout");
mWindowManager.addView(mLayout, lp);
}
if (eventText.toLowerCase().contains("navigate")) {
Log.d(TAG, "Removing the layout");
if (mLayout != null && mLayout.getRootView() != null) {
mWindowManager.removeView(mLayout.getRootView());
}
}
}
@Override
public void onInterrupt() {
}
}
However, my code breaks and it is obviously wrong. It fails when it tries to remove the layout. (And also, is it adding the same layout multiple times?). And are there any performance issues I should consider?
Following is the exception which is thrown when I try to remove the frame layout:
03-08 22:28:10.375 24266-24266/im.avi.todolist E/AndroidRuntime:
FATAL EXCEPTION: main
Process: im.avi.todolist, PID: 24266
java.lang.IllegalArgumentException: View=android.widget.FrameLayout{3695c2 V.E...... ......I. 0,0-0,0} not attached to window manager
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:473)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:382)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:119)
at im.avi.todolist.GlobalActionBarService.onAccessibilityEvent(GlobalActionBarService.java:77)
at android.accessibilityservice.AccessibilityService$2.onAccessibilityEvent(AccessibilityService.java:1449)
at android.accessibilityservice.AccessibilityService$IAccessibilityServiceClientWrapper.executeMessage(AccessibilityService.java:1585)
at com.android.internal.os.HandlerCaller$MyHandler.handleMessage(HandlerCaller.java:37)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)