Нарисуйте панель навигации (и другие приложения) в версии Android> = 5

Я хотел бы нарисовать значок (указатель мыши) на экране над другими приложениями из службы. Я реализовал функциональность, и я могу рисовать поверх экрана, кроме панели навигации. Я исследовал несколько других вопросов здесь и пробовал TYPE_SYSTEM_OVERLAY , TYPE_TOAST , TYPE_SYSTEM_ERROR и некоторые другие типы окон без успеха.

Я не пытаюсь захватить фокус, просто рисуя указатель мыши на экране на секунду или два. Когда я пытаюсь нарисовать панель навигации, она просто исчезает (фактически, RelativeLayout заканчивается на границе с навигационной панелью – даже когда я указываю ручное измерение для высоты). На скриншоте ниже показан указатель руки в нижней правой части экрана. Это настолько низко, насколько я могу позиционировать его. Обратите внимание, что я не пытаюсь скрыть панель навигации в своем приложении, пытаясь нарисовать другие приложения.

Наложение-указатель на экране

Я даже попытался установить параметры смещения xpos и ypos в экземпляре WindowManager.LayoutParams , но это просто смещает макет и все еще идет ниже панели навигации).

Параметры макета, которые я использую, чтобы показать это окно:

  WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, PixelFormat.TRANSPARENT); 

Затем я добавляю RelativeLayout с этими параметрами в WindowManager: windowManager.addView(relativeLayout, params);

После долгих войн мне удалось получить правильные флаги, чтобы заставить его работать. Он почти работает (для большинства приложений). Следующий код (пример для обработчика кнопок):

 @Override public void onClick(View view) { if (_windowManager == null) { _windowManager = (WindowManager) MainActivity.this.getSystemService(Context.WINDOW_SERVICE); } WindowManager.LayoutParams params; // create the view on the first try if (_overlayView == null) { ImageView hand; _overlayView = new FrameLayout(MainActivity.this); hand = new ImageView(MainActivity.this); hand.setImageResource(R.drawable.icon_hand_pointer); int w = hand.getDrawable().getIntrinsicWidth(); int h = hand.getDrawable().getIntrinsicHeight(); _overlayView.addView(hand); params = new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT); params.width = w; params.height = h; params.gravity = Gravity.LEFT | Gravity.TOP; params.x = _xOffset; params.y = _yOffset; _windowManager.addView(_overlayView, params); } else { // move the view params = (WindowManager.LayoutParams) _overlayView.getLayoutParams(); params.x = _xOffset; params.y = _yOffset; _windowManager.removeView(_overlayView); _overlayView.setLayoutParams(params); _windowManager.addView(_overlayView, params); } _xOffset += 40; _yOffset += 100; } 

Вот скриншот этого кода, работающего в приложении (вы можете увидеть наложение рук, это на Nexus 5 с Android 6.0.1: Введите описание изображения здесь

Панель навигации внизу – это то, что невозможно нарисовать, потому что элементы, нарисованные выше, могут препятствовать доступу к домашней кнопке, кнопке «Назад» и т. Д. Но вы можете сделать свою деятельность полноэкранной, что означает, что она скроет кнопки навигации до тех пор, пока Вы прокручиваете снизу, чтобы вы могли свободно рисовать в любом месте экрана

EDIT: Я нашел несколько похожих вопросов, и у этого есть ответ: Рисовать растровые изображения поверх панели навигации в Android . Ответ заключался в том, чтобы добавить ay offset, это размер панели навигации.