
Facebook одним из первых продемонстрировал реализацию «Drawing over other apps». Данную возможность разработчики сейчас используют в различных типах приложений — от боковых смарт-меню до записи экрана. В этой статье, хочу продеменстрировать процесс написания приложения-поверх-других-приложений на примере «анти-шпионской» программы Khameleon.
Для начала обозначу цели приложения, который будет реализован как пример приложения-поверх-других-приложений. Допустим нужно, чтобы рядом стоящие люди не могли с легкостью видеть контент моего смарфтона, пока я им пользуюсь. То есть необходима возможность:
- Скрывать часть дисплея, чтобы видеть только необходимую область
- Вместо скрытой области, показывать любой желаемый контент (например заданную веб страницу)
Примерно это может выглядеть так:

С функционалом приложения определились — теперь приступим к самому туториалу. Для написания приложения-поверх-других-приложений есть две самых главных составляющих:
- Service, через который ведется основной контроль и логика приложения
- Layout, который собственно и является GUI
Перед тем как реализовывать эти два компонента, необходимо получить разрешение для приложения-поверх-других-приложений. Для этого в AndroidManifest.xml необходимо добавить:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
А для API > 23, т.е. Android M, нужно запросить разрешение в главном Activity:
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, ЛЮБОЙ_ЗАДАННЫЙ_INT);
После того как разрешение получено, укажем Layout, который нужно отобразвить на экране (многие элементы убраны для демонстрации):
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/black"> <View android:id="@+id/grab" android:layout_width="40dp" android:layout_height="40dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="10dp"/> </RelativeLayout>
В корневой RelativeLayout (по вашему усмотрению) можно поместить любые View'шки как обычно. View с id="@+id/grab" нам нужен для того, чтобы показать как динамично менять размеры Layout. То есть через эту View'шку можно будет расстягивать и сжимать корневой RelativeLayout.
Как только у нас есть минимальный Layout, необходимо реализовать самый обычный Service. Единственная особенность сервиса в добавлении ранее созданного Layout:
@Override public void onCreate(){ super.onCreate(); manager = (WindowManager) getSystemService(WINDOW_SERVICE); params = new WindowManager.LayoutParams( screenWidth, // Ширина экрана screenHeight, // Высота экрана WindowManager.LayoutParams.TYPE_PHONE, // Говорим, что приложение будет поверх других. В поздних API > 26, данный флаг перенесен на TYPE_APPLICATION_OVERLAY WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, // Необходимо для того чтобы TouchEvent'ы в пустой области передавались на другие приложения PixelFormat.TRANSLUCENT); // Само окно прозрачное // Задаем позиции для нашего Layout topParams.gravity = Gravity.TOP | Gravity.RIGHT; params.x = 0; params.y = 0; // Отображаем наш Layout rootView = (RelativeLayout) LayoutInflater.from(this).inflate(R.layout.наш_лэйаут, null); windowManager.addView(rootView, params);
На данном этапе наш Layout успешно отображается поверх других приложении. Теперь рассмотрим как можно динамично менять размеры нашего Layout:
rootView.findViewById(R.id.grab).setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) { // Обрабатываем позицию касания и обноваляем размер Layout'а params.height = (int) motionEvent.getRawY() manager.updateView(topView, topParams); } return true; } });
Если потянуть за край Layout вверх или вниз, его высота соответственно сжимается и расширяется.
Мы рассмотрели минимальные необходимые шаги для написания приложения-поверх-других-приложений. Полный код для приложенения Khameleon, продемонстрированный выше, можно найти здесь.

