Membuat jendela hamparan sistem (selalu di atas)

285

Saya mencoba untuk membuat tombol selalu-op-top / diklik-gambar yang tetap di atas semua jendela sepanjang waktu.

Bukti konsepnya adalah

Saya telah sukses dan memiliki layanan yang berjalan sekarang. Layanan ini menampilkan beberapa teks di sudut kiri atas layar sepanjang waktu sementara pengguna dapat secara bebas berinteraksi dengan aplikasi lainnya dengan cara normal.

Apa yang saya lakukan adalah subkelas ViewGroupdan menambahkannya ke root window manager dengan flag TYPE_SYSTEM_OVERLAY. Sekarang saya ingin menambahkan tombol / diklik-gambar di tempat teks ini yang dapat menerima peristiwa sentuhan itu sendiri. Saya mencoba mengganti "onTouchEvent" untuk keseluruhan ViewGrouptetapi tidak menerima acara apa pun.

Bagaimana saya bisa menerima acara hanya pada bagian tertentu dari grup tampilan selalu di atas saya? Mohon saran.

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
sumber
2
@coreSOLO, saya harap Anda mendapatkan jawaban Anda, pertanyaan saya yang mirip aneh tidak mendapat jawaban. :) +1
st0le
3
@ st0le Saya berjanji akan menghabiskan malam dan siang sampai saya menemukan solusinya dan membaginya dengan Anda :)
coreSOLO
1
@ st0le Ok mungkin Anda dan saya bisa menggali bersama-sama, berikan saya tautan pertanyaan Anda dan beri tahu saya berapa banyak kemajuan yang dapat Anda buat ...
coreSOLO
ini tidak banyak: - \ stackoverflow.com/questions/3732935/…
st0le
3
Mengejutkan bahwa Anda onDraw()dipanggil. Bukankah dispatchDraw()seharusnya diganti? Lihat groups.google.com/forum/?fromgroups#!topic/android-developers/…
faizal

Jawaban:

158

Ini mungkin solusi bodoh. Tapi itu berhasil. Jika Anda dapat memperbaikinya, beri tahu saya.

OnCreate Layanan Anda: Saya telah menggunakan WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCHbendera. Ini adalah satu-satunya perubahan dalam layanan.

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

Sekarang, Anda akan mulai mendapatkan setiap klik acara. Jadi, Anda perlu memperbaikinya di event handler Anda.

Di acara sentuh ViewGroup Anda

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

Anda juga mungkin perlu menambahkan izin ini ke manifes Anda:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Sarwar Erfan
sumber
1
@ Wangwang: kesalahan apa yang Anda dapatkan? Kode ini tidak independen, Anda perlu menempatkannya di proyek Anda dengan nama file yang sesuai dalam proyek yang sesuai.
Sarwar Erfan
4
@pengwang: Temukan implementasi paling sederhana di sini: docs.google.com/...
Sarwar Erfan
6
seluruh kode sudah benar, saya menemukan kesalahan saya, saya lupa tautan <menggunakan-izin android: name = "android.permission.SYSTEM_ALERT_WINDOW" /> Sarwar Erfan saya pikir Anda mengedit jawaban Anda, itu bisa menjadi lebih indah
pengwang
1
Jawaban ini sangat membantu, kecuali untuk satu hal. Seperti yang digunakan dalam kode, WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH, menurut dokumentasi, "tidak akan menerima gerakan naik / turun / turun penuh". Dengan kata lain, tidak mungkin mendeteksi gesekan atau apa pun selain ACTION_DOWN. Yah saya tahu bahwa itu mungkin untuk mendeteksi gesekan karena Wave Launcher menggunakan konsep serupa ini dan mereka dapat mendeteksi gesekan. Adakah yang bisa menjelaskan kepada saya bagaimana ini bekerja?
Brian
6
@SarwarErfan - Saya menggunakan ini penyumbatannya dengan sempurna pada 2.3 tetapi acara onTouch tidak dikunci secara geet pada Android 4.0, 1nd 4.1. Tolong bantu
Sanjay Singh
66

Mengikuti jawaban @ Sam Lu, Memang Android 4.x memblokir tipe tertentu dari mendengarkan acara sentuh luar, tetapi beberapa jenis, seperti TYPE_SYSTEM_ALERT, masih melakukan pekerjaan.

Contoh

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

Izin

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
amirlazarovich
sumber
5
Ini membuat layar saya digantung .. Gagasan
Viswanath Lekshmanan
Pos yang bagus. Semoga ini tidak dinonaktifkan di rilis mendatang juga.
Cookster
Animasi tidak akan bekerja di atasnya ... :( Dan itu tidak dapat menangkap klik pada setiap tampilan di dalamnya di 4.2.X. Ada saran?
Kamran Ahmed
Ini berfungsi tetapi ketika saya menggunakan pintasan itu (yaitu Peringatan Tingkat Sistem), dialog lainnya tidak ditampilkan. Mengapa
Chimu
@ Arju apa maksudmu? apakah Anda mencoba menghapusnya?
amirlazarovich
18

Dimulai dengan Android 4.x, tim Android memperbaiki masalah keamanan potensial dengan menambahkan fungsi baru adjustWindowParamsLw()yang akan ditambahkan FLAG_NOT_FOCUSABLE, FLAG_NOT_TOUCHABLEdan menghapus FLAG_WATCH_OUTSIDE_TOUCHbendera untuk TYPE_SYSTEM_OVERLAYwindows.

Artinya, sebuah TYPE_SYSTEM_OVERLAYjendela tidak akan menerima acara sentuh apa pun pada platform ICS dan, tentu saja, menggunakan TYPE_SYSTEM_OVERLAYbukanlah solusi yang bisa diterapkan untuk ICS dan perangkat masa depan.

Sam Lu
sumber
4
Jadi apa saja alternatifnya?
radhoo
1
Lihat pertanyaan ini tentang ICS: stackoverflow.com/questions/9656185/type-system-overlay-in-ics
clemp6r
13

Saya salah satu pengembang SDK Tooleap . Kami juga menyediakan cara bagi pengembang untuk selalu menampilkan di jendela dan tombol atas, dan kami telah menangani situasi yang sama.

Satu masalah yang belum dijawab oleh jawaban di sini adalah "Tombol Terjamin" Android.

Tombol aman memiliki filterTouchesWhenObscuredproperti yang berarti tidak dapat berinteraksi dengan, jika ditempatkan di bawah jendela, bahkan jika jendela itu tidak menerima sentuhan apa pun. Mengutip dokumentasi Android:

Menentukan apakah akan menyaring sentuhan saat jendela tampilan dikaburkan oleh jendela lain yang terlihat. Jika disetel ke true, tampilan tidak akan menerima sentuhan setiap kali bersulang, dialog atau jendela lain muncul di atas jendela tampilan. Lihat dokumentasi keamanan {@link android.view.View} untuk detail lebih lanjut.

Contoh dari tombol tersebut adalah tombol instal ketika Anda mencoba menginstal apks pihak ketiga. Aplikasi apa pun dapat menampilkan tombol seperti itu jika menambahkan tata letak tampilan pada baris berikut:

android:filterTouchesWhenObscured="true"

Jika Anda menampilkan jendela selalu-di-atas di atas "Tombol Aman", maka semua bagian tombol aman yang ditutupi oleh overlay tidak akan menangani sentuhan apa pun, meskipun overlay itu tidak dapat diklik. Jadi jika Anda berencana untuk menampilkan jendela seperti itu, Anda harus menyediakan cara bagi pengguna untuk memindahkan atau mengabaikannya. Dan jika sebagian overlay Anda transparan, perhatikan bahwa pengguna Anda mungkin bingung mengapa tombol tertentu di aplikasi yang mendasarinya tidak bekerja untuknya secara tiba-tiba.

Danny
sumber
Bisakah Anda menjawab pertanyaan saya: stackoverflow.com/questions/28964771/…
Nauman Afzaal
ada beberapa aktivitas di android 10 yang tampilan overlay tidak dapat tunjukkan di atas mereka dapatkah Anda jelaskan alasannya atau lihat pertanyaan saya di sini akan sangat membantu stackoverflow.com/questions/59598264/…
Mateen Chaudhry
12

BEKERJA SELALU DI TOMBOL GAMBAR TOP

pertama-tama maaf untuk bahasa inggris saya

saya mengedit kode Anda dan membuat tombol gambar bekerja yang mendengarkan acara sentuh-nya tidak memberikan kontrol sentuh untuk elemen latar belakangnya.

juga memberikan sentuhan pendengar untuk keluar dari elemen lain

perubahan tombol di bagian bawah dan kiri

Anda dapat mengejar perubahan tetapi Anda harus mengejar koordinat dalam acara sentuhan di elemen 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
sumber
Ini berfungsi, tetapi bagaimana saya bisa memastikan gambar saya diklik dan bukan sesuatu di sekitar gambar?
Liam W
@LiamW, koordinat sentuhan dibandingkan dengan kangaroo.getWidth () dalam contoh ini. Anda dapat menyimpulkan apa yang akan dibandingkan dalam kode Anda sendiri berdasarkan di mana Anda menggambar gambar Anda.
Yevgeny Simkin
Sangat bagus! Bekerja dengan sempurna.
Yevgeny Simkin
Apa versi minimum android ini berfungsi? Saya sedang mengerjakan penulisan ini tetapi saya baru di android jadi saya memiliki waktu pemula.
Noitidart
6

Sebenarnya, Anda dapat mencoba WindowManager.LayoutParams.TYPE_SYSTEM_ERROR alih-alih TYPE_SYSTEM_OVERLAY. Mungkin terdengar seperti retasan, tetapi memungkinkan Anda menampilkan tampilan di atas segalanya dan masih mendapatkan acara sentuh.

Ov3r1oad
sumber
1
Saya mencoba segala sesuatu untuk membuatnya bekerja, tetapi tidak berhasil .... tetapi menambahkan TYPE_SYSTEM_ERROR melakukan pekerjaan .... Sebenarnya TYPE_SYSTEM_OVERLAY memblokir sentuhan ..... +1.
Robi Kumar Tomar
6

TYPE_SYSTEM_OVERLAY Konstanta ini sudah tidak digunakan lagi sejak API level 26. Sebagai gantinya, gunakan TYPE_APPLICATION_OVERLAY. atau ** untuk pengguna di bawah dan di atas 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
sumber
5

Coba ini. Bekerja dengan baik di ICS. Jika Anda ingin menghentikan layanan cukup klik pemberitahuan yang dihasilkan di bilah status.

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

MEMPERBARUI

Sampel sini

Untuk membuat tampilan overlay, saat mengatur LayoutParams JANGAN mengatur tipe ke TYPE_SYSTEM_OVERLAY.

Instead set it to TYPE_PHONE.

Use the following flags:

FLAG_NOT_TOUCH_MODAL

FLAG_WATCH_OUTSIDE_TOUCH
Viswanath Lekshmanan
sumber
Ini tidak berfungsi untuk saya, Layar saya tidak berinteraksi dengan latar belakang. Metode lain yang Anda tahu ...
Vinuthan
@Vinuthan Whats output Anda, apakah itu merespons
Viswanath Lekshmanan
Tidak, itu tidak merespons. Saya telah mengisi aktivitas saya di atas hingga setengah layar sehingga saya dapat berinteraksi dengan latar belakang, tetapi saya tidak dapat berinteraksi dengan latar belakang.
Vinuthan
FLAG_WATCH_OUTSIDE_TOUCH mencegah Anda berinteraksi dengan latar belakang
Richard Le Mesurier
1
TYPE_PHONE berfungsi untuk saya - sekarang sentuhan dikirimkan - setidaknya saya dapat mengetuk tombol;) terima kasih!
vir us
3

Berikut adalah beberapa solusi sederhana, Yang Anda butuhkan adalah mengembang tata letak XML seperti yang Anda lakukan pada daftar adaptor, hanya membuat tata letak XML untuk mengembangnya. Inilah kode yang Anda butuhkan.

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

}
pengguna1668168
sumber
3

Menemukan perpustakaan yang melakukan hal itu: https://github.com/recruit-lifestyle/FloatingView

Ada contoh proyek di folder root. Saya menjalankannya dan berfungsi sesuai kebutuhan. Latar belakang dapat diklik - meskipun aplikasi lain.

masukkan deskripsi gambar di sini

AlikElzin-kilaka
sumber
Terima kasih atas rekomendasinya, saya hanya berusaha mencari proyek hebat ini.
upupming
1

Coba kode saya, setidaknya itu memberi Anda string sebagai overlay, Anda bisa menggantinya dengan tombol atau gambar. Anda tidak akan percaya ini adalah LOL aplikasi android pertama saya. Bagaimanapun jika Anda lebih berpengalaman dengan aplikasi Android daripada saya, silakan coba

  • mengubah parameter 2 dan 3 di "WindowManager baru. LayoutParams"
  • coba beberapa pendekatan acara yang berbeda
coreSOLO
sumber
akhirnya saya tidak menemukan waktu untuk mengejar ini, maka saya masih kekurangan detailnya ...
st0le
1

Jika ada yang masih membaca utas ini dan tidak bisa menjalankannya, saya sangat menyesal untuk memberitahu Anda cara untuk mencegat acara gerak ini dianggap sebagai bug dan diperbaiki di android> = 4.2.

Acara gerak yang Anda sadap, meskipun memiliki tindakan sebagai ACTION_OUTSIDE, mengembalikan 0 di getX dan getY. Ini berarti Anda tidak dapat melihat semua posisi gerakan di layar, Anda juga tidak dapat melakukan apa pun. Saya tahu dokter mengatakan itu akan mendapatkan x dan y, tetapi kenyataannya itu TIDAK AKAN. Tampaknya ini untuk memblokir logger kunci.

Jika ada yang punya solusi, silakan tinggalkan komentar Anda.

ref: Mengapa ACTION_OUTSIDE mengembalikan 0 setiap kali di KitKat 4.4.2?

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

Nick Jian
sumber
1

dengan menggunakan layanan Anda dapat mencapai ini:

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
sumber
1

Jawaban @Sarwar Erfan tidak berfungsi lagi karena Android tidak mengizinkan penambahan tampilan dengan WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY ke jendela yang dapat disentuh lagi bahkan dengan WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH.

Saya menemukan solusi untuk masalah ini. Anda dapat memeriksanya di pertanyaan berikut

Saat menambahkan tampilan ke jendela dengan WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, itu tidak mendapatkan acara sentuh

patilmandar2007
sumber
Solusi yang Anda
referensikan
@AhmadShahwaiz Silakan periksa tautan lagi Saya telah menambahkan komentar untuk masalah yang Anda sebutkan di sana
patilmandar2007
Ya, sekarang sudah berfungsi. Tetapi tidak mendapatkan respons panggilan balik setelah memanggil startActivityForResult (maksud, OVERLAY_REQ_CODE); dalam metode void onActivityResult (int requestCode, int resultCode, Intent data) terlindungi.
Ahmad Shahwaiz
@AhmadShahwaiz Perubahan yang disebutkan dalam tautan akan dipanggil menggunakan aktivitas di mana kita mendapatkan panggilan balik dalam metode onActivityResult. Jika Anda memeriksa izin di atas dalam Layanan maka Anda mungkin perlu menambahkan aktivitas transparan boneka untuk memulai dari layanan, yang dapat meminta pengguna untuk Izin dan kemudian di aktivitas boneka onActivityResult Anda akan mendapatkan hasil dari pengguna. Setelah Anda harus memberi tahu layanan Anda untuk menambahkan tampilan ke jendela atau tidak tergantung pada respons pengguna
patilmandar2007
1

Ini adalah pertanyaan lama tetapi baru-baru ini Android memiliki dukungan untuk Bubbles. Bubbles akan segera diluncurkan tetapi saat ini pengembang dapat mulai menggunakannya. Mereka dirancang untuk menjadi alternatif untuk menggunakan SYSTEM_ALERT_WINDOW. Aplikasi seperti (Facebook Messenger dan MusiXMatch menggunakan konsep yang sama).

Gelembung

Gelembung dibuat melalui API Pemberitahuan, Anda mengirim pemberitahuan seperti biasa. Jika Anda ingin menggelembung, Anda harus melampirkan beberapa data tambahan ke dalamnya. Untuk informasi lebih lanjut tentang Bubbles Anda dapat pergi ke Panduan Pengembang Android resmi tentang Bubbles .

Xenolion
sumber