Наложение системы Android не отображается за пределами моего приложения


Мне нужно показать окно наложения системы поверх всех запущенных приложений. Он отлично работает, но только когда активность моего приложения находится на переднем плане. Вот код, который я использую:

params = new WindowManager.LayoutParams(
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.WRAP_CONTENT,
                    WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                    WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | 
                    WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
                    WindowManager.LayoutParams.FLAG_DIM_BEHIND |
                    WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | 
                    WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
                    WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
                    WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD,
                    PixelFormat.TRANSLUCENT);

params.gravity = Gravity.CENTER | Gravity.TOP;
params.dimAmount = 0.3f;
wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);

    mainAlertView = View.inflate(ctx, R.layout.system_alert_view, null);

    wm.addView(mainAlertView, params);

Вид, добавленный в WindowManager, содержит пустой LinearLayout, к которому я добавляю дочерние представления во время выполнения:

    mainAlertLayout.addView(childView);

Манифест xml имеет SYSTEM_ALERT_WINDOW определенное разрешение:

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

Все это великолепно работает, пока моя деятельность работает на переднем плане. Как только я переключаюсь на любое другое приложение или домашний экран, никакого наложения не происходит. показанный. Я отладил код, и он действительно работает под управлением wm.addView (), и его не бросает никаких исключений. Я также поиграл с флагами LayoutParams (удалены KEEP_SCREEN_ON и связанные с ними и т. д.), Но ничего не изменилось.

Android 4.4.2 fwiw

2 2

2 ответа:

Вам нужно создать service, чтобы оверлей системы( предупреждение) отображался даже при закрытии приложения.

Создайте простой сервис, который я вызову как FloatingService, который покажет наложение (alert), когда onStartCommand будет вызван . Return START_STICKY, чтобы служба продолжала работать в фоновом режиме.

    public class FloatingService extends Service {
      private WindowManager windowManager;
      private View floatingView;

     WindowManager.LayoutParams params;
    @Override
     public IBinder onBind(Intent intent) {
        return null;
      }

     @Override
     public int onStartCommand(Intent intent, int flag, int startId){
      // show the alert her
      windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
       // use your custom view here
        floatingView = View.inflate(getBaseContext(),R.layout.floating_layout,null);            //floatingView.setOnTouchListener(mOnTouchListener);
        params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD,
                PixelFormat.TRANSLUCENT);
           params.gravity = Gravity.CENTER | Gravity.CENTER;
        // add the view to window manger
        windowManager.addView(floatingView, params);
      return START_STICKY;
     }
 }

Добавьте прослушиватель в представление, чтобы при необходимости закрыть наложение(оповещение)

      floatingView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                windowManager.removeView(floatingView);
                floatingView = null;
            }
        });

Наконец, зарегистрируйте службу в манифесте

 <service android:name="com.example.app.services.FloatingService" />

И System Alert разрешение

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

Проблема заключалась в том, что я запускал вызов addView() в методе Post () главного представления:

mainView.post(new Runnable() {
 public void run() {
  wm.add(mainView);
 }
);

Вместо этого, если я просто запускаю его в главном потоке, он работает нормально. Я использую de.greenrobot.eventbus и его очень просто разместить Runnable к шине событий и обеспечить его выполнение в основном потоке:

public void onEventMainThread(UIRunnableEvent event) {
    event.r.run();
}

public static class UIRunnableEvent {
    protected Runnable r;

    protected UIRunnableEvent(Runnable r) {
        this.r = r;
    }
}