Tworzenie okna nakładki systemowej (zawsze u góry)

285

Próbuję utworzyć zawsze przycisk / obraz, który zawsze jest na górze, i który pozostaje cały czas nad wszystkimi oknami.

Dowód koncepcji jest

Odniosłem sukces i mam teraz działającą usługę. Serwis wyświetla cały tekst w lewym górnym rogu ekranu, podczas gdy użytkownik może swobodnie wchodzić w interakcje z resztą aplikacji w normalny sposób.

To, co robię, to podklasa ViewGroupi dodaj ją do menedżera okien root z flagą TYPE_SYSTEM_OVERLAY. Teraz chcę dodać przycisk / klikalny obraz zamiast tego tekstu, który może odbierać zdarzenia dotykowe na sobie. Próbowałem przesłonić „onTouchEvent” dla całości, ViewGroupale nie otrzymało żadnego zdarzenia.

Jak mogę odbierać zdarzenia tylko w niektórych częściach mojej grupy zawsze na wierzchu? Uprzejmie sugeruję.

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
źródło
2
@coreSOLO, mam nadzieję, że dostaniesz odpowiedź, moje dziwnie podobne pytania nie otrzymały żadnej odpowiedzi. :) +1
st0le
3
@ st0le Obiecuję, że spędzę noc i dzień, aż znajdę rozwiązanie i podzielę się nim z tobą :)
coreSOLO
1
@ st0le Ok, może ty i ja możemy to wykopać razem, dać mi link do twojego pytania i dać mi znać, jak duży postęp byłeś w stanie zrobić ...
coreSOLO
jego niewiele: - \ stackoverflow.com/questions/3732935/…
st0le
3
Zaskakujące onDraw()jest to, że nazywasz się. dispatchDraw()Zamiast tego nie należy go zastępować? Zobacz groups.google.com/forum/?fromgroups#!topic/android-developers/…
faizal

Odpowiedzi:

158

To może być głupie rozwiązanie. Ale to działa. Jeśli możesz to poprawić, daj mi znać.

OnCreate of Service: Użyłem WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCHflagi. To jedyna zmiana usługi.

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

Teraz zaczniesz otrzymywać każde zdarzenie kliknięcia. Tak więc musisz sprostować w module obsługi zdarzeń.

W zdarzeniu dotykowym 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;
}

Konieczne może być również dodanie tego uprawnienia do manifestu:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Sarwar Erfan
źródło
1
@pengwang: jakie masz błędy? Ten kod nie jest niezależny, musisz umieścić je w projekcie z odpowiednimi nazwami plików w ramach odpowiedniego projektu.
Sarwar Erfan
4
@pengwang: Znajdź najprostszą implementację tutaj: docs.google.com/…
Sarwar Erfan
6
cały kod jest poprawny, znajduję mój błąd, zapominam link <uses-permission android: name = "android.permission.SYSTEM_ALERT_WINDOW" /> Sarwar Erfan Myślę, że edytujesz swoją odpowiedź, może stać się cudowniejsza
pengwang
1
Ta odpowiedź jest bardzo pomocna, z wyjątkiem jednej rzeczy. Jak użyto w kodzie, WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, zgodnie z dokumentacją, „nie otrzyma pełnego gestu góra / ruch / dół”. Innymi słowy, nie można wykryć przeciągnięć ani niczego innego niż ACTION_DOWN. Wiem, że można wykryć przeciągnięcia, ponieważ Wave Launcher stosuje tę podobną koncepcję i jest w stanie wykryć przeciągnięcia. Czy ktoś może mi wyjaśnić, jak to działa?
Brian
6
@SarwarErfan - Użyłem tego jego korkowania idealnie w 2.3, ale zdarzenie onTouch nie jest wywoływane geeting na Androida 4.0, 1 i 4.1. Proszę o pomoc
Sanjay Singh
66

Po odpowiedzi @Sam Lu, Indeed Android 4.x blokuje niektórym typom odsłuchiwanie zewnętrznych zdarzeń dotykowych, ale niektóre typy, takie jak TYPE_SYSTEM_ALERT, nadal wykonują zadanie.

Przykład

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

Uprawnienia

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
amirlazarowicz
źródło
5
Powoduje to,
Wspaniały post. Mamy nadzieję, że nie zostanie to również wyłączone w przyszłych wydaniach.
Cookster
Animacje na nim nie działają ... :( I nie jest w stanie wyłapać kliknięć w żadnym widoku w 4.2.X. Wszelkie sugestie?
Kamran Ahmed
Działa, ale kiedy używam tego skrótu (tj. System Level Alert), inne okna dialogowe nie są wyświetlane. Czemu ?
Chimu,
@Arju, co masz na myśli? próbujesz to usunąć?
amirlazarovich
18

Zaczynając z Android 4.x, Android zespół naprawiono potencjalny problem bezpieczeństwa, dodając nową funkcję adjustWindowParamsLw(), w którym będzie dodać FLAG_NOT_FOCUSABLE, FLAG_NOT_TOUCHABLEi usunąć FLAG_WATCH_OUTSIDE_TOUCHflagi na TYPE_SYSTEM_OVERLAYoknach.

Oznacza to, że TYPE_SYSTEM_OVERLAYokno nie otrzyma żadnego zdarzenia dotyku na platformie ICS i, oczywiście, użycie TYPE_SYSTEM_OVERLAYnie jest praktycznym rozwiązaniem dla ICS i przyszłych urządzeń.

Sam Lu
źródło
4
więc jakie są alternatywy?
radhoo,
1
Zobacz to pytanie dotyczące ICS: stackoverflow.com/questions/9656185/type-system-overlay-in-ics
clemp6r
13

Jestem jednym z programistów Tooleap SDK . Zapewniamy również programistom możliwość wyświetlania zawsze w górnych oknach i przyciskach, i poradziliśmy sobie z podobną sytuacją.

Jednym z problemów, których tutaj nie rozwiązano, jest problem „zabezpieczonych przycisków” Androida.

Zabezpieczone przyciski mają filterTouchesWhenObscuredwłaściwość, co oznacza, że ​​nie można z nimi wchodzić w interakcje, jeśli zostaną umieszczone pod oknem, nawet jeśli okno to nie zostanie dotknięte. Cytując dokumentację Androida:

Określa, czy filtrować akcenty, gdy okno widoku jest zasłonięte innym widocznym oknem. Ustawienie wartości true powoduje, że widok nie zostanie dotknięty za każdym razem, gdy nad oknem widoku pojawi się toast, okno dialogowe lub inne okno. Więcej informacji można znaleźć w dokumentacji bezpieczeństwa {@link android.view.View}.

Przykładem takiego przycisku jest przycisk instalacyjny , gdy próbujesz zainstalować aplikacje innych firm. Każda aplikacja może wyświetlić taki przycisk, jeśli doda do układu widoku następujący wiersz:

android:filterTouchesWhenObscured="true"

Jeśli wyświetlasz okno „Zawsze na wierzchu” nad „Zabezpieczonym przyciskiem”, więc wszystkie zabezpieczone części przycisku, które są pokryte nakładką, nie obsługują żadnych dotknięć, nawet jeśli nakładki tej nie można kliknąć. Jeśli więc planujesz wyświetlić takie okno, powinieneś dać użytkownikowi możliwość jego przeniesienia lub odrzucenia. A jeśli część twojej nakładki jest przezroczysta, weź pod uwagę, że użytkownik może być zdezorientowany, dlaczego pewien przycisk w podstawowej aplikacji nie działa dla niego nagle.

Danny
źródło
Czy możesz mi odpowiedzieć na moje pytanie: stackoverflow.com/questions/28964771/...
Nauman Afzaal
w Androidzie 10 jest jakaś aktywność, której widok nakładki nie może wyświetlić się nad nimi. Czy możesz podać przyczynę lub zobaczyć moje pytanie tutaj, będzie to bardzo pomocne stackoverflow.com/questions/59598264/...
Mateen Chaudhry
12

ZAWSZE PRACUJĄC NA GÓRNYM PRZYCISKU OBRAZU

przede wszystkim przepraszam za mój angielski

edytuję kody i sprawiam, że działający przycisk obrazu, który nasłuchuje jego zdarzenia dotykowego, nie daje kontroli dotykowej jego elementom tła.

Daje także dotykowym słuchaczom inne elementy

przyciski są dolne i lewe

możesz wymieniać alingi, ale musisz dotykać kordinatów w zdarzeniu dotykowym w elemencie 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;
    }
}
Onur Öztürk
źródło
To działa, ale jak mogę się upewnić, że mój obraz został kliknięty, a nie coś wokół obrazu?
Liam W
@LiamW, współrzędne dotyku są porównywane z kangaroo.getWidth () w tym przykładzie. Możesz wydedukować, z czym możesz to porównać we własnym kodzie na podstawie tego, gdzie rysujesz obraz.
Jewgienij Simkin
Bardzo dobrze! Działa świetnie.
Jewgienij Simkin
Jaka jest minimalna wersja Androida, na której działa? Pracuję nad napisaniem tego, ale jestem nowy na Androida, więc mam czas dla początkujących.
Noitidart,
6

W rzeczywistości możesz wypróbować WindowManager.LayoutParams.TYPE_SYSTEM_ERROR zamiast TYPE_SYSTEM_OVERLAY. Może to zabrzmieć jak włamanie, ale pozwala wyświetlać widok nad wszystkim i nadal otrzymywać zdarzenia dotykowe.

Ov3r1oad
źródło
1
Próbowałem wszystkiego, aby działało, ale bez powodzenia .... ale dodanie TYPE_SYSTEM_ERROR wykonało zadanie .... Właściwie TYPE_SYSTEM_OVERLAY blokował dotyk ..... + 1.
Robi Kumar Tomar
6

TYPE_SYSTEM_OVERLAY Ta stała była przestarzała od poziomu API 26. Zamiast tego użyj TYPE_APPLICATION_OVERLAY. lub ** dla użytkowników poniżej i powyżej Androida 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
źródło
5

Spróbuj tego. Działa dobrze w ICS. Jeśli chcesz zatrzymać usługę, po prostu kliknij powiadomienie wygenerowane na pasku stanu.

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

AKTUALIZACJA

Próbka tutaj

Aby utworzyć widok nakładki, podczas konfigurowania LayoutParams NIE ustawiaj typu na TYPE_SYSTEM_OVERLAY.

Instead set it to TYPE_PHONE.

Use the following flags:

FLAG_NOT_TOUCH_MODAL

FLAG_WATCH_OUTSIDE_TOUCH
Viswanath Lekshmanan
źródło
To nie działa dla mnie, Mój ekran nie wchodzi w interakcje z tłem. Każda inna metoda, którą znasz ...
Vinuthan,
@Vututhan Jaki jest twój wynik, czy on odpowiada
Viswanath Lekshmanan
Nie, nie odpowiada. Ustawiłem aktywność powyżej połowy ekranu, aby móc wchodzić w interakcje z tłem, ale nie mogę wchodzić w interakcje z tłem.
Vinuthan
FLAG_WATCH_OUTSIDE_TOUCH uniemożliwia interakcję z tłem
Richard Le Mesurier
1
TYPE_PHONE działało dla mnie - teraz poprawki są dostarczane - przynajmniej jestem w stanie nacisnąć przycisk;) dzięki!
vir us
3

Oto kilka prostych rozwiązań: Wszystko czego potrzebujesz to nadmuchać układ XML, tak jak robisz to w przypadku list adapterów, po prostu utwórz układ XML, aby go napompować. Oto kod, którego potrzebujesz.

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

}
użytkownik1668168
źródło
3

Znaleziono bibliotekę, która właśnie to robi: https://github.com/recruit-lifestyle/FloatingView

W folderze głównym znajduje się przykładowy projekt. Uruchomiłem go i działa zgodnie z wymaganiami. Tło można kliknąć - nawet jeśli jest to inna aplikacja.

wprowadź opis zdjęcia tutaj

AlikElzin-kilaka
źródło
Dzięki za rekomendację, właśnie próbowałem znaleźć ten świetny projekt.
poprawa
1

Wypróbuj mój kod, przynajmniej daje ci ciąg jako nakładkę, możesz bardzo dobrze zastąpić go przyciskiem lub obrazem. Nie uwierzysz, że to moja pierwsza aplikacja LOL na Androida. W każdym razie, jeśli masz większe doświadczenie z aplikacjami na Androida niż ja, spróbuj

  • zmiana parametrów 2 i 3 w „nowym WindowManager.LayoutParams”
  • wypróbuj inne podejście do zdarzenia
coreSOLO
źródło
w końcu nie znalazłem czasu, aby się tym zająć, dlatego wciąż brakuje mi szczegółów ...
st0le,
1

Jeśli ktoś nadal czyta ten wątek i nie jest w stanie go uruchomić, przykro mi powiedzieć, że w ten sposób przechwycenie zdarzenia ruchu jest uważane za błąd i poprawkę w Androidzie> = 4.2.

Przechwycone zdarzenie ruchu, chociaż ma akcję ACTION_OUTSIDE, zwraca 0 w getX i getY. Oznacza to, że nie widzisz całej pozycji ruchu na ekranie, ani nie możesz nic zrobić. Wiem, że doktor powiedział, że dostanie xiy, ale prawda jest taka, że ​​NIE. Wydaje się, że ma to na celu zablokowanie rejestratora kluczy.

Jeśli ktoś ma obejście tego problemu, zostaw swój komentarz.

ref: Dlaczego ACTION_OUTSIDE zwraca 0 za każdym razem na KitKat 4.4.2?

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

Nick Jian
źródło
1

korzystając z usługi możesz to osiągnąć:

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;
        }
    }
}
Akshay Paliwal
źródło
1

Odpowiedź @ Sarwar Erfan już nie działa, ponieważ Android nie pozwala na dodawanie widoku za pomocą WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY do okna, aby można go było dotykać już nawet przy WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH.

Znalazłem rozwiązanie tego problemu. Możesz to sprawdzić w następującym pytaniu

Podczas dodawania widoku do okna za pomocą WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY nie pojawia się zdarzenie dotykowe

patilmandar2007
źródło
Twoje
polecane
@AhmadShahwaiz Sprawdź ponownie link Dodałem komentarz do problemu, o którym tam wspomniałeś
patilmandar2007
Tak, teraz działa. Ale brak odpowiedzi oddzwonienia po wywołaniu startActivityForResult (intent, OVERLAY_REQ_CODE); w chronionej metodzie onActivityResult (int requestCode, int resultCode, Intent data).
Ahmad Shahwaiz
@AhmadShahwaiz Zmiany wymienione w linku należy wywoływać za pomocą działania, w którym otrzymujemy wywołanie zwrotne w metodzie onActivityResult. Jeśli sprawdzasz powyższe uprawnienia w usłudze, może być konieczne dodanie fałszywego przezroczystego działania w celu uruchomienia z usługi, które może poprosić użytkownika o pozwolenie, a następnie w przypadku manekina onActivityResult otrzymasz wynik od użytkownika. Po tym, jak będziesz musiał powiadomić usługę, aby dodać widok do okna lub nie, w zależności od odpowiedzi użytkownika
patilmandar2007
1

To stare pytanie, ale ostatnio Android obsługuje Bubbles. Wkrótce zostaną uruchomione bąbelki, ale obecnie programiści mogą zacząć z nich korzystać. Są one zaprojektowane jako alternatywa dla używania SYSTEM_ALERT_WINDOW. Aplikacje takie jak (Facebook Messenger i MusiXMatch używają tej samej koncepcji).

Bąbelki

Pęcherzyki są tworzone za pośrednictwem interfejsu API powiadomień, a powiadomienie wysyłane jest normalnie. Jeśli chcesz, aby bąbelkowała, musisz dołączyć do niej dodatkowe dane. Aby uzyskać więcej informacji o Bubbles, przejdź do oficjalnego Przewodnika programisty Androida na Bubbles .

Xenolion
źródło