Создание системного оверлея (всегда сверху)

285

Я пытаюсь создать постоянно активируемую кнопку / кликабельное изображение, которое постоянно остается поверх всех окон.

Доказательство концепции

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

Я делаю подкласс ViewGroupи добавляю его в корневой оконный менеджер с флагом TYPE_SYSTEM_OVERLAY. Теперь я хочу добавить кнопку / clickable-изображение вместо этого текста, который может получать сенсорные события сам по себе. Я попытался переопределить «onTouchEvent» для всего, ViewGroupно он не получает никакого события.

Как я могу получать события только в определенных частях моей группы с постоянным просмотром? Пожалуйста, предложите.

public class HUD extends Service {
    HUDView mView;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();
        mView = new HUDView(this);
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                0,
//              WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
//                      | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.RIGHT | Gravity.TOP;
        params.setTitle("Load Average");
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(mView, params);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(getBaseContext(),"onDestroy", Toast.LENGTH_LONG).show();
        if(mView != null)
        {
            ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(mView);
            mView = null;
        }
    }
}

class HUDView extends ViewGroup {
    private Paint mLoadPaint;

    public HUDView(Context context) {
        super(context);
        Toast.makeText(getContext(),"HUDView", Toast.LENGTH_LONG).show();

        mLoadPaint = new Paint();
        mLoadPaint.setAntiAlias(true);
        mLoadPaint.setTextSize(10);
        mLoadPaint.setARGB(255, 255, 0, 0);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawText("Hello World", 5, 15, mLoadPaint);
    }

    @Override
    protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //return super.onTouchEvent(event);
        Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();
        return true;
    }
}
coreSOLO
источник
2
@coreSOLO, я надеюсь, вы получите ответ, мои странно похожие вопросы не получили никакого ответа. :) +1
0
3
@ st0le Я обещаю, что проведу ночь и день, пока не найду решение и не поделюсь им с вами :)
coreSOLO
1
@ st0le Хорошо, может быть, вы и я сможем разобраться вместе, дайте мне ссылку на ваш вопрос и дайте мне знать, какой прогресс вы смогли сделать ...
coreSOLO
это не очень много: - \ stackoverflow.com/questions/3732935/…
st0le
3
Удивительно, что тебя onDraw()зовут. Не должно dispatchDraw()быть отменено вместо этого? См. Groups.google.com/forum/?fromgroups#!topic/android-developers/…
faizal,

Ответы:

158

Это может быть глупым решением. Но это работает. Если вы можете улучшить его, пожалуйста, дайте мне знать.

На создание вашего сервиса: я использовал WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCHфлаг. Это единственное изменение в обслуживании.

@Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();
        mView = new HUDView(this);
        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                PixelFormat.TRANSLUCENT);
        params.gravity = Gravity.RIGHT | Gravity.TOP;
        params.setTitle("Load Average");
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
        wm.addView(mView, params);
    }

Теперь вы начнете получать каждое событие клика. Итак, вам нужно исправить в вашем обработчике событий.

В вашем сенсорном событии ViewGroup

@Override
public boolean onTouchEvent(MotionEvent event) {

    // ATTENTION: GET THE X,Y OF EVENT FROM THE PARAMETER
    // THEN CHECK IF THAT IS INSIDE YOUR DESIRED AREA


    Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();
    return true;
}

Также вам может понадобиться добавить это разрешение в ваш манифест:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Сарвар Эрфан
источник
1
@pengwang: какие ошибки вы получаете? Этот код не является независимым, вам нужно поместить их в ваш проект с соответствующими именами файлов под соответствующим проектом.
Сарвар Эрфан
4
@pengwang: здесь вы найдете простейшую реализацию: docs.google.com/…
Сарвар Эрфан,
6
весь код верен, я нахожу свою ошибку, я забыл ссылку <использование-разрешения android: name = "android.permission.SYSTEM_ALERT_WINDOW" /> Sarwar Erfan я думаю, что вы редактируете свой ответ, он может стать более замечательным
pengwang
1
Этот ответ очень полезен, за исключением одного. Как используется в коде, WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, согласно документации, «не получит полный жест вверх / перемещение / вниз». Другими словами, невозможно обнаружить считывания или что-либо еще, кроме ACTION_DOWN. Ну, я знаю, что можно обнаруживать пролистывания, потому что Wave Launcher использует эту похожую концепцию, и они способны обнаруживать пролистывания. Может кто-нибудь объяснить мне, как это работает?
Брайан
6
@SarwarErfan - я использовал его пробку отлично на 2.3, но событие onTouch не вызывается на Android 4.0, 1-ой 4.1. Пожалуйста, помогите
Санджай Сингх
66

После ответа @Sam Lu, действительно, Android 4.x блокирует определенные типы от прослушивания внешних событий касания, но некоторые типы, такие как TYPE_SYSTEM_ALERT, все еще делают работу.

пример

    WindowManager.LayoutParams params = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
            PixelFormat.TRANSLUCENT);

    WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
    View myView = inflater.inflate(R.layout.my_view, null);
    myView.setOnTouchListener(new OnTouchListener() {
       @Override
       public boolean onTouch(View v, MotionEvent event) {
           Log.d(TAG, "touch me");
           return true;
       }
     });

    // Add layout to window manager
    wm.addView(myView, params);

права доступа

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
amirlazarovich
источник
5
Это заставляет мой экран
зависать
Отличный пост. Надеюсь, это не будет отключено в будущих версиях.
Cookster
Анимации не будут работать на нем ... :( И он не может поймать клики на любом представлении в нем на 4.2.X. Есть предложения?
Кямран Ахмед
Это работает, но когда я использую этот ярлык (то есть оповещение системного уровня), другие диалоговые окна не отображаются. Зачем ?
Chimu
@ Арджу, что ты имеешь в виду? Вы пытаетесь удалить это?
Амирлазарович
18

Начиная с Android 4.x, Android команда исправлена потенциальная проблема безопасности, добавив новую функцию , adjustWindowParamsLw()в которой он будет добавлять FLAG_NOT_FOCUSABLE, FLAG_NOT_TOUCHABLEи удалять FLAG_WATCH_OUTSIDE_TOUCHфлаги для TYPE_SYSTEM_OVERLAYокон.

То есть TYPE_SYSTEM_OVERLAYокно не получит никакого сенсорного события на платформе ICS и, конечно, его использование TYPE_SYSTEM_OVERLAYне является работоспособным решением для ICS и будущих устройств.

Сэм Лу
источник
4
так какие есть альтернативы?
Radhoo
1
См. Этот вопрос о ICS: stackoverflow.com/questions/9656185/type-system-overlay-in-ics
clemp6r
13

Я один из разработчиков Tooleap SDK . Мы также предоставляем разработчикам возможность всегда отображать верхние окна и кнопки, и мы столкнулись с подобной ситуацией.

Одной из проблем, на которые не были даны ответы, является проблема защищенных кнопок Android.

Защищенные кнопки имеют filterTouchesWhenObscuredсвойство, которое означает, что они не могут взаимодействовать, если находятся под окном, даже если это окно не получает никаких прикосновений. Цитирование документации Android:

Указывает, следует ли фильтровать касания, когда окно представления скрыто другим видимым окном. Если установлено значение true, представление не будет получать прикосновения всякий раз, когда над окном представления появляется всплывающее окно, диалоговое окно или другое окно. Обратитесь к {@link android.view.View} документации по безопасности для получения дополнительной информации.

Примером такой кнопки является кнопка установки , когда вы пытаетесь установить сторонние apks. Любое приложение может отобразить такую ​​кнопку, если добавить к макету вида следующую строку:

android:filterTouchesWhenObscured="true"

Если вы отображаете всегда поверх окна поверх «Защищенной кнопки», то все защищенные части кнопок, которые покрыты наложением, не будут обрабатывать никаких касаний, даже если это наложение не активировано. Поэтому, если вы планируете отображать такое окно, вы должны предоставить пользователю возможность его переместить или закрыть. И если часть вашего оверлея прозрачна, учтите, что ваш пользователь может быть сбит с толку, почему определенная кнопка в базовом приложении неожиданно для него не работает.

Дэнни
источник
Можете ли вы ответить на мой вопрос: stackoverflow.com/questions/28964771/…
Науман Афзаал
в андроиде 10 есть активность, которую вид сверху не может отображать над ними. Можете ли вы сказать причину или посмотреть мой вопрос здесь, это будет очень полезно stackoverflow.com/questions/59598264/…
Mateen Chaudhry
12

РАБОТАЙТЕ ВСЕГДА НА КНОПКАХ TOP IMAGE

прежде всего извините за мой английский

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

также это дает слушателям прикосновение к другим элементам

кнопки внизу и слева

Вы можете изменить настройки, но вам нужно изменить кординацию в событии touch в элементе if

import android.annotation.SuppressLint;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Toast;

public class HepUstte extends Service {
    HUDView mView;

    @Override
    public void onCreate() {
        super.onCreate();   

        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();

        final Bitmap kangoo = BitmapFactory.decodeResource(getResources(),
                R.drawable.logo_l);


        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                kangoo.getWidth(), 
                kangoo.getHeight(),
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                 PixelFormat.TRANSLUCENT);






        params.gravity = Gravity.LEFT | Gravity.BOTTOM;
        params.setTitle("Load Average");
        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);



        mView = new HUDView(this,kangoo);

        mView.setOnTouchListener(new OnTouchListener() {


            @Override
            public boolean onTouch(View arg0, MotionEvent arg1) {
                // TODO Auto-generated method stub
                //Log.e("kordinatlar", arg1.getX()+":"+arg1.getY()+":"+display.getHeight()+":"+kangoo.getHeight());
                if(arg1.getX()<kangoo.getWidth() & arg1.getY()>0)
                {
                 Log.d("tıklandı", "touch me");
                }
                return false;
            }
             });


        wm.addView(mView, params);



        }



    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

}



@SuppressLint("DrawAllocation")
class HUDView extends ViewGroup {


    Bitmap kangoo;

    public HUDView(Context context,Bitmap kangoo) {
        super(context);

        this.kangoo=kangoo;



    }


    protected void onDraw(Canvas canvas) {
        //super.onDraw(canvas);


        // delete below line if you want transparent back color, but to understand the sizes use back color
        canvas.drawColor(Color.BLACK);

        canvas.drawBitmap(kangoo,0 , 0, null); 


        //canvas.drawText("Hello World", 5, 15, mLoadPaint);

    }


    protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
    }

    public boolean onTouchEvent(MotionEvent event) {
        //return super.onTouchEvent(event);
       // Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();

        return true;
    }
}
Онур Эзтюрк
источник
Это работает, но как я могу убедиться, что мое изображение было нажато, а не что-то вокруг изображения?
Лиам W
@LiamW, координаты касания сравниваются с kangaroo.getWidth () в этом примере. Вы можете сделать вывод, с чем сравнивать, в своем собственном коде, основываясь на том, где вы рисуете свое изображение.
Евгений Симкин
Очень хорошо! Работает отлично.
Евгений Симкин
На какой минимальной версии Android это работает? Я работаю над написанием этого, но я новичок в Android, поэтому у меня время для начинающих.
Noitidart
6

На самом деле вы можете попробовать WindowManager.LayoutParams.TYPE_SYSTEM_ERROR вместо TYPE_SYSTEM_OVERLAY. Это может звучать как хак, но оно позволяет отображать представление поверх всего и по-прежнему получать сенсорные события.

Ov3r1oad
источник
1
Я пытался сделать все, чтобы это работало, но безуспешно ... но добавление TYPE_SYSTEM_ERROR сделало эту работу .... На самом деле TYPE_SYSTEM_OVERLAY блокировала касание ..... + 1.
Роби Кумар Томар
6

TYPE_SYSTEM_OVERLAY Эта константа устарела начиная с уровня API 26. Вместо этого используйте TYPE_APPLICATION_OVERLAY. или ** для пользователей ниже и выше Android 8

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
    LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}
arwTheDev
источник
5

Попробуй это. Прекрасно работает в ICS. Если вы хотите остановить службу, просто нажмите на уведомление, созданное в строке состояния.

 public class HUD extends Service
 {
    protected boolean foreground = false;
    protected boolean cancelNotification = false;
    private Notification notification;
    private View myView;
    protected int id = 0;
    private WindowManager wm;
    private WindowManager.LayoutParams params;
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
       // System.exit(0);
        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_SHORT).show();
        params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
        params.gravity=Gravity.TOP|Gravity.LEFT;
    wm = (WindowManager) getSystemService(WINDOW_SERVICE);
    inflateview();
    foregroundNotification(1);
    //moveToForeground(1,n,true);
    }     
   @Override
    public void onDestroy() {
        super.onDestroy();
        ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(0);
        Toast.makeText(getBaseContext(),"onDestroy", Toast.LENGTH_SHORT).show();
        if(myView != null)
        {
            ((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(myView);
            myView = null;
        }
    }
    protected Notification foregroundNotification(int notificationId) 
   {    
    notification = new Notification(R.drawable.ic_launcher, "my Notification", System.currentTimeMillis());    
        notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_ONLY_ALERT_ONCE;   
        notification.setLatestEventInfo(this, "my Notification", "my Notification", notificationIntent());          
        ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).notify(id, notification);            
        return notification;
    }
    private PendingIntent notificationIntent() {
        Intent intent = new Intent(this, stopservice.class);    
        PendingIntent pending = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);    
        return pending;
    }
    public void inflateview()
    {
         LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
            myView = inflater.inflate(R.layout.activity_button, null);
            myView.setOnTouchListener(new OnTouchListener() {
               @Override
               public boolean onTouch(View v, MotionEvent event) {
                   Toast.makeText(getBaseContext(),"onToasttt", Toast.LENGTH_SHORT).show();
                   return false;
               }
             });
            // Add layout to window manager
            wm.addView(myView, params); 
    }
}

ОБНОВИТЬ

Образец здесь

Чтобы создать вид наложения, при настройке LayoutParams НЕ устанавливайте тип TYPE_SYSTEM_OVERLAY.

Instead set it to TYPE_PHONE.

Use the following flags:

FLAG_NOT_TOUCH_MODAL

FLAG_WATCH_OUTSIDE_TOUCH
Вишванат Лекшманан
источник
Это не работает для меня, мой экран не взаимодействует с фоном. Любой другой метод, который вы знаете ...
Vinuthan
@Vinuthan Каков ваш вывод, отвечает ли он
Вишванат Лекшманан
Нет, не отвечает. Я добавил свою активность выше половины экрана, чтобы я мог взаимодействовать с фоном, но я не могу взаимодействовать с фоном.
Vinuthan
FLAG_WATCH_OUTSIDE_TOUCH не позволяет вам взаимодействовать с фоном
Ричард Ле Мезурье
1
TYPE_PHONE работал для меня - теперь касания доставлены - по крайней мере, я могу нажать кнопку;) спасибо!
Вир нас
3

Вот простое решение. Все, что вам нужно, это накачать XML-макет точно так же, как вы делаете это для адаптеров списков, просто создайте XML-макет, чтобы его накачать. Вот код, который вам нужен.

 public class HUD extends Service {
    View mView;

    LayoutInflater inflate;
    TextView t;
    Button b;

    @Override
    public void onCreate() {
        super.onCreate();   

        Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();


        WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);

        Display display = wm.getDefaultDisplay();  get phone display size
        int width = display.getWidth();  // deprecated - get phone display width
        int height = display.getHeight(); // deprecated - get phone display height 


        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                width, 
                height,
                WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                |WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                 PixelFormat.TRANSLUCENT);


        params.gravity = Gravity.LEFT | Gravity.CENTER;
        params.setTitle("Load Average");

        inflate = (LayoutInflater) getBaseContext()
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        mView = inflate.inflate(R.layout.canvas, null);

        b =  (Button) mView.findViewById(R.id.button1);
        t = (TextView) mView.findViewById(R.id.textView1);
        b.setOnClickListener(new OnClickListener() {

        public void onClick(View v) {
            // TODO Auto-generated method stub
            t.setText("yes you click me ");
        }
       });

        wm.addView(mView, params);

        }



    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

}
user1668168
источник
3

Нашел библиотеку, которая делает именно это: https://github.com/recruit-lifestyle/FloatingView

В корневой папке есть пример проекта. Я запустил его, и он работает как требуется. Фон кликабелен - даже если это другое приложение.

введите описание изображения здесь

AlikElzin-kilaka
источник
Спасибо за рекомендацию, я просто пытался найти этот отличный проект.
upupming
1

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

  • изменение параметров 2 и 3 в «новом WindowManager.LayoutParams»
  • попробуйте другой подход
coreSOLO
источник
В конце концов, я не нашел времени заняться этим, поэтому мне все еще не хватает деталей ...
2010 г., 11:00
1

Если кто-то еще читает эту ветку и не может заставить ее работать, мне очень жаль сообщать вам, что этот способ перехвата события движения считается ошибкой и исправлением в Android> = 4.2.

Событие движения, которое вы перехватили, хотя и имеет действие ACTION_OUTSIDE, возвращает 0 в getX и getY. Это означает, что вы не можете видеть все позиции движения на экране, и вы ничего не можете сделать. Я знаю, что док сказал, что получит х и у, но правда в том, что НЕ БУДЕТ. Кажется, что это заблокировать регистратор ключей.

Если у кого-то есть обходной путь, пожалуйста, оставьте свой комментарий.

ref: Почему ACTION_OUTSIDE каждый раз возвращает 0 на KitKat 4.4.2?

https://code.google.com/p/android/issues/detail?id=72746

Ник Цзянь
источник
1

с помощью сервиса вы можете добиться этого:

public class PopupService extends Service{

    private static final String TAG = PopupService.class.getSimpleName();
    WindowManager mWindowManager;
    View mView;
    String type ;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
//        registerOverlayReceiver();
        type = intent.getStringExtra("type");
        Utils.printLog("type = "+type);
        showDialog(intent.getStringExtra("msg"));
        return super.onStartCommand(intent, flags, startId);
    }

    private void showDialog(String aTitle)
    {
        if(type.equals("when screen is off") | type.equals("always"))
        {
            Utils.printLog("type = "+type);
            PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
            WakeLock mWakeLock = pm.newWakeLock((PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "YourServie");
            mWakeLock.acquire();
            mWakeLock.release();
        }

        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mView = View.inflate(getApplicationContext(), R.layout.dialog_popup_notification_received, null);
        mView.setTag(TAG);

        int top = getApplicationContext().getResources().getDisplayMetrics().heightPixels / 2;

        LinearLayout dialog = (LinearLayout) mView.findViewById(R.id.pop_exit);
//        android.widget.LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) dialog.getLayoutParams();
//        lp.topMargin = top;
//        lp.bottomMargin = top;
//        mView.setLayoutParams(lp);

        final EditText etMassage = (EditText) mView.findViewById(R.id.editTextInPopupMessageReceived);

        ImageButton imageButtonSend = (ImageButton) mView.findViewById(R.id.imageButtonSendInPopupMessageReceived);
//        lp = (LayoutParams) imageButton.getLayoutParams();
//        lp.topMargin = top - 58;
//        imageButton.setLayoutParams(lp);
        imageButtonSend.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                Utils.printLog("clicked");
//                mView.setVisibility(View.INVISIBLE);
                if(!etMassage.getText().toString().equals(""))
                {
                    Utils.printLog("sent");
                    etMassage.setText("");
                }
            }
        });

        TextView close = (TextView) mView.findViewById(R.id.TextViewCloseInPopupMessageReceived);
        close.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                hideDialog();   
            }
        });

        TextView view = (TextView) mView.findViewById(R.id.textviewViewInPopupMessageReceived);
        view.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View arg0) {
                hideDialog();   
            }
        });

        TextView message = (TextView) mView.findViewById(R.id.TextViewMessageInPopupMessageReceived);
        message.setText(aTitle);

        final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(
        ViewGroup.LayoutParams.MATCH_PARENT,
        ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
        WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
        WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
//                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON ,
        PixelFormat.RGBA_8888);

        mView.setVisibility(View.VISIBLE);
        mWindowManager.addView(mView, mLayoutParams);
        mWindowManager.updateViewLayout(mView, mLayoutParams);

    }

    private void hideDialog(){
        if(mView != null && mWindowManager != null){
            mWindowManager.removeView(mView);
            mView = null;
        }
    }
}
Акшай Паливал
источник
1

Ответ @Sarwar Erfan больше не работает, так как Android не позволяет добавлять представление с WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY к окну, чтобы оно больше не было доступно даже с WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH.

Я нашел решение этой проблемы. Вы можете проверить это в следующем вопросе

При добавлении представления в окно с помощью WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY событие касания не отображается

patilmandar2007
источник
Ваше упомянутое решение также не работает в «
Зефире»
@AhmadShahwaiz Пожалуйста, проверьте ссылку еще раз. Я добавил комментарий к проблеме, о которой вы упомянули,
Patilmandar2007
Да, теперь это работает. Но не получить ответ на обратный вызов после вызова startActivityForResult (intent, OVERLAY_REQ_CODE); в защищенном void метод onActivityResult (int requestCode, int resultCode, Intent data).
Ахмад Шахваиз,
@AhmadShahwaiz Изменения, упомянутые в ссылке, должны вызываться с помощью действия, когда мы получаем обратный вызов в методе onActivityResult. Если вы проверяете указанное выше разрешение в Сервисе, то вам может понадобиться добавить фиктивную прозрачную активность, которая будет запущена из сервиса, которая может запросить у пользователя Разрешение, а затем в фиктивной активности onActivityResult вы получите результат от пользователя. После того, как вам потребуется уведомить ваш сервис о добавлении вида в окно или нет, в зависимости от ответа пользователя
Patilmandar2007
1

Это старый вопрос, но недавно в Android появилась поддержка Bubbles. Вскоре будут запущены пузыри, но в настоящее время разработчики могут начать использовать их. Они предназначены для альтернативы их использованию SYSTEM_ALERT_WINDOW. Такие приложения, как (Facebook Messenger и MusiXMatch используют одну и ту же концепцию).

Пузыри

Пузыри создаются с помощью API уведомлений, вы отправляете уведомление как обычно. Если вы хотите, чтобы он пузырился, вам нужно приложить к нему дополнительные данные. Для получения дополнительной информации о Bubbles вы можете обратиться к официальному руководству Android для разработчиков по Bubbles .

Xenolion
источник