Липкое наложение без WindowManager.LayoutParams.TYPE_PHONE - PullRequest
8 голосов
/ 20 марта 2019

Под липкой я подразумеваю окно, которое не закрывается вызовом намерения модуля запуска (intent.addCategory(Intent.CATEGORY_HOME).

Ранее это было сделано с WindowManager.LayoutParams.TYPE_PHONE, но этот тип устарел и выдаетисключение для API 28:

WindowManager $ BadTokenException ... отказано в разрешении для типа окна 2002

Поведение по-прежнему возможно, поскольку Messenger Facebook делает это с помощью чата.", исходя из предположения, что Facebook не получает разрешений системного приложения, поскольку оно предустановлено на большом количестве дисков.

Использование WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY не работает (т.е. нажатие кнопки home также скрывает наложениеокно).

Редактировать : Вопрос в том, как создать оверлейное окно, которое не удаляется, когда пользователь нажимает кнопку «Домой» / вызывает намерение программы запуска.Это не относится к TYPE_APPLICATION_OVERLAY, это относится к TYPE_PHONE, но это устарело.

Редактировать 2: Видимо, это работает для некоторых людей, это код, который ям работает:

class MyClass {

    var params: WindowManager.LayoutParams = WindowManager.LayoutParams(
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
            else WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG,
            WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
            PixelFormat.TRANSLUCENT
    ).apply {
        windowAnimations = android.R.style.Animation_Dialog
        gravity = Gravity.CENTER or Gravity.CENTER
        x = 0
        y = 0
    }
    var windowManager: WindowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager

    init {
        val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        rootView = layoutInflater.inflate(R.layout.view_overlay, null)
        windowManager.addView(rootView, params)
    }

}

Ответы [ 3 ]

1 голос
/ 28 марта 2019

Ссылка: https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html

TYPE_PHONE

public static final int TYPE_APPLICATION_OVERLAY

Эта константа устарела на уровне API 26 .

для несистемных приложений. Вместо этого используйте TYPE_APPLICATION_OVERLAY.

Тип окна: телефон. These are non-application windows providing user interaction with the phone (в частности входящие звонки). Эти окна обычно располагаются над всеми приложениями, но за строкой состояния. В многопользовательских системах отображается на всех окнах пользователей.

TYPE_APPLICATION_OVERLAY

public static final int TYPE_APPLICATION_OVERLAY

Тип окна: окна наложения приложения отображаются над всеми окнами активности (типы от FIRST_APPLICATION_WINDOW до LAST_APPLICATION_WINDOW), но под критическими системными окнами, такими как строка состояния или IME.

Система может изменить положение, размер или видимость этих окон в любое время, чтобы уменьшить визуальный беспорядок для пользователя и управлять ресурсами.

Требуется разрешение Manifest.permission.SYSTEM_ALERT_WINDOW.

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

Система отрегулирует важность процессов с этим типом окна, чтобы уменьшить вероятность того, что убийца с нехваткой памяти убьет их.

В многопользовательских системах отображается только на экране пользователя-владельца.

мы должны использовать TYPE APPLICATION OVERLAY на устройстве Oreo или позже у нас уже есть пример как Manoj Perumarath gived

вам нужно определить параметры окна так:

//if device is Oreo or latter if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT);

//or else
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.TYPE_PHONE,
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT);

Manifest.xml

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
//...other stuff
<service
android:name=".serviceClass"
android:enabled="true"
android:exported="false"/>

MainActivity

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, APP_PERMISSION_REQUEST);
}
else
{
 //start service
}

Читать один раз

0 голосов
/ 06 апреля 2019

Решение: Не надувайте оверлей непосредственно над другими приложениями.

Обычно при использовании TYPE_APPLICATION_OVERLAY все еще ведет себя как TYPE_PHONE, проблема с моим случаем состояла в том, что я отображал свое представление (windowManager.addView(rootView, params)), когда действие из другого приложения находилось на переднем плане, и Android присоединяет представление к текущее действие переднего плана, поэтому, когда пользователь выходит из этого действия (например, нажав кнопку «Домой»), система также удаляет оверлей из моего приложения. Решение для меня было очень конкретным, у меня нет общего решения, но эта информация должна помочь людям найти его.

0 голосов
/ 28 марта 2019

В Manifest добавить разрешение

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

В активности запуска вы должны запросить canDrawOverlays Разрешения`

 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && 
 !Settings.canDrawOverlays(this)) {


        //If the draw over permission is not available open the settings screen
        //to grant the permission.
        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
                Uri.parse("package:" + getPackageName()));
        startActivityForResult(intent, CODE_DRAW_OVER_OTHER_APP_PERMISSION);
    } else {
        initializeView();
    }

Затем внутри вашего сервиса

 //Inflate the floating view layout
    mFloatingView = 
    LayoutInflater.from(this).inflate(R.layout.layout_floating_widget, null);

    int LAYOUT_TYPE;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        LAYOUT_TYPE = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
    } else {
        LAYOUT_TYPE = WindowManager.LayoutParams.TYPE_PHONE;
    }
    //Add the view to the window.
    final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            LAYOUT_FLAG ,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            PixelFormat.TRANSLUCENT);

    //Specify the view position
    params.gravity = Gravity.TOP | Gravity.LEFT;        //Initially view will be added to top-left corner
    params.x = 0;
    params.y = 100;

    //Add the view to the window
    mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
    mWindowManager.addView(mFloatingView, params);

Это не будет отклонено, так как пользователь нажимает Home Key.

Убедитесь, что ваш плавающий виджет определен как service, иначе он не сможет выжить, когда мало памяти / изменение конфигурациивопросыТакже зарегистрируйте услугу внутри манифеста

   <service
            android:name=".MyWidget"
            android:enabled="true"
            android:exported="false"/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...