Створення вікна накладення системи (завжди вгорі)


285

Я намагаюся створити кнопку, яка завжди працює вгорі, та кнопку, на яку можна натиснути, яка постійно залишатиметься над усіма вікнами.

Доказом концепції є

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

Я роблю підклас ViewGroupі додаю його до менеджера кореневих вікон із прапором TYPE_SYSTEM_OVERLAY. Тепер я хочу додати зображення / клік-зображення замість цього тексту, який може отримувати сенсорні події на собі. Я намагався змінити "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;
    }
}

2
@coreSOLO, я сподіваюся, що ти отримаєш відповідь, на мої дивно подібні запитання не отримав жодної відповіді. :) +1
st0le

3
@ st0le Я обіцяю, що проведу свою ніч і день, поки не знайду рішення і поділюся з вами :)
coreSOLO

1
@ st0le Добре, можливо, ми з вами зможемо розкопати їх разом, дайте мені посилання свого питання і дайте мені знати, скільки прогресу ви змогли досягти ...
coreSOLO

Його не було так багато: - \ stackoverflow.com/questions/3732935 / ...
st0le

3
Дивно, що вас onDraw()дзвонять. Чи не dispatchDraw()слід замінювати це замість? Дивіться groups.google.com/forum/?fromgroups#!topic/android-developers/…
фазал

Відповіді:


158

Це може бути дурним рішенням. Але це працює. Якщо ви можете вдосконалити, будь ласка, повідомте мене про це.

OnCreate вашої служби: я використав 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 / ...
Сарвар Erfan

6
весь код правильний, я знаходжу свою помилку, я забуваю посилання <використання-дозволу android: name = "android.permission.SYSTEM_ALERT_WINDOW" /> Сарвар Ерфан, я думаю, ви редагуєте свою відповідь, вона може стати прекраснішою
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"/>


Чудовий пост. Сподіваємось, це не буде відключено і в майбутніх випусках.
Кукстер

Анімації не працюватимуть на ній ... :( І він не може зафіксувати кліки на будь-якому перегляді в ньому на 4.2.X. Будь-які пропозиції?
Камран Ахмед

Він працює, але коли я використовую цей ярлик (тобто попередження рівня системи), інші діалоги не відображаються. Чому?
Чіму

@Arju, що ти маєш на увазі? ви намагаєтесь її видалити?
амірлазарович

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

Я один із розробників SDK Tooleap . Ми також надаємо спосіб розробникам завжди відображатись на верхніх вікнах та кнопках, і ми мали справу з подібною ситуацією.

Однією з проблем, відповіді на які тут не вирішено, є проблема Android "Захищені кнопки".

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

Вказує, чи слід фільтрувати дотики, коли інше видиме вікно переглядає затемнення. Якщо встановлено значення true, подання не буде отримувати дотики кожного разу, коли над вікном перегляду з’явиться тост, діалогове вікно чи інше вікно. Докладніші відомості див. У документації щодо безпеки {@link android.view.View}.

Прикладом такої кнопки є кнопка встановлення, коли ви намагаєтесь встановити сторонні програми apks. Будь-яка програма може відобразити таку кнопку, якщо додати в макет перегляду наступний рядок:

android:filterTouchesWhenObscured="true"

Якщо ви відображаєте вікно, що знаходиться завжди вгорі над "Захищеною кнопкою", то всі захищені частини кнопки, накриті накладкою, не оброблятимуть жодних дотиків, навіть якщо це накладення не можна натискати. Отже, якщо ви плануєте відображати таке вікно, ви повинні надати користувачеві спосіб перемістити його або відхилити його. І якщо частина вашої накладки прозора, врахуйте, що ваш користувач може заплутатися, чому певна кнопка в базовому додатку не працює для нього раптово.


Чи можете ви відповісти на моє запитання: stackoverflow.com/questions/28964771 / ...
Науман Afzaal

є деяка активність в android 10, що перегляд накладок не може відображатись над ними, ви можете, будь ласка, поясніть причину або подивіться на моє запитання тут, це буде дуже корисно stackoverflow.com/questions/59598264/…
Mateen Chaudhry

12

РОБОТА РОБОТА НА КНОПКІ ЗОБРАЖЕННЯ ЗОБРАЖЕННЯ

передусім вибачте за мою англійську

я редагую ваші коди і роблю робочу кнопку, яка слухає його сенсорну подію, не дають сенсорного контролю його фоновим елементам.

Крім того, це дає можливість слухачам доторкнутися до інших елементів

Зміни кнопок знизу та зліва

Ви можете змінювати зміни, але вам потрібно змінити кординати у випадку дотику в елементі 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;
    }
}

Це працює, але як я можу переконатися, що моє зображення було натиснене, а не щось навколо зображення?
Liam W

@LiamW, координати дотику порівнюються з kangaroo.getWidth () у цьому прикладі. Ви можете визначити, з чим порівнювати його у власному коді, залежно від того, де ви малюєте зображення.
Євген Симкін

Дуже хороша! Працює чудово.
Євген Симкін

Яка мінімальна версія для Android працює на цьому? Я працюю над написанням цього, але я нове для андроїда, тому у мене є час для початківців.
Noitidart

6

Насправді ви можете спробувати WindowManager.LayoutParams.TYPE_SYSTEM_ERROR замість TYPE_SYSTEM_OVERLAY. Це може здатися злому, але це дозволяє вам відображати перегляд поверх всього і все одно отримувати сенсорні події.


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;
}

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 Який ваш результат, чи відповідає він
Viswanath Lekshmanan

Ні, це не відповідає. Я вклав свою активність вище половини екрана, щоб я міг взаємодіяти з фоном, але я не можу взаємодіяти з фоном.
Vinuthan

FLAG_WATCH_OUTSIDE_TOUCH заважає вам взаємодіяти з фоном
Річард Ле Месюр'є

1
TYPE_PHONE працював на мене - зараз дотики доставлені - принаймні я можу натиснути кнопку;) дякую!
vir us

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;
    }

}

3

Знайдено бібліотеку, яка робить саме це: https://github.com/recruit-lifestyle/FloatingView

Зразок проекту в кореневій папці. Я запустив його, і він працює як потрібно. Фон можна натискати, навіть якщо це інший додаток.

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


Дякую за рекомендацію, я просто намагався знайти цей чудовий проект.
оновлення


1

Добре спробуйте мій код, принаймні він дає вам рядок як накладення, ви можете дуже добре замінити його кнопкою або зображенням. Ви не вірите, що це моя перша в історії Android програма LOL. У будь-якому разі, якщо ви маєте більше досвіду з додатками для Android, ніж я, будь ласка, спробуйте

  • зміна параметрів 2 і 3 у "new WindowManager.LayoutParams"
  • спробуйте інший підхід до події

Я врешті-решт не знайшов часу для цього, тому я все ще обмежений у своїх деталях ...
st0le

1

Якщо хтось ще читає цю тему і не в змозі змусити її працювати, я дуже шкодую, що цей спосіб перехоплення події руху вважається помилкою та виправленням в android> = 4.2.

Подія руху, яку ви перехопили, хоча має дію як ACTION_OUTSIDE, поверніть 0 в getX та getY. Це означає, що ви не можете бачити всю позицію руху на екрані, а також нічого не можете зробити. Я знаю, що доктор сказав, що він отримає х і у, але правда НЕ БУДЕ. Здається, що це блокувати реєстратор ключів.

Якщо у когось є рішення, будь ласка, залиште свій коментар.

ref: Чому ACTION_OUTSIDE щоразу повертає 0 на KitKat 4.4.2?

https://code.google.com/p/android/isissue/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, це не отримує сенсорну подію



@AhmadShahwaiz Перевірте посилання ще раз я додав коментар до проблеми, про яку ви згадали
patilmandar2007

Так, зараз це працює. Але не отримувати відповіді на зворотний дзвінок після виклику startActivityForResult (намір, 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 сповіщень, ви надсилаєте своє повідомлення як звичайне. Якщо ви хочете, щоб він міхур, вам потрібно прикласти до нього кілька додаткових даних. Щоб отримати додаткові відомості про бульбашки, перейдіть до офіційного Посібника для розробників Android на Bubbles .

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.