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



Я пытаюсь создать всегда-op-top button / clickable-image
которая остается поверх всех окон все время.



доказательство
концепция - это




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



что я
делать-это подкласс ViewGroup и добавить его в корень оконный менеджер
флаг TYPE_SYSTEM_OVERLAY. Теперь я хочу добавить кнопку / clickable-image
вместо этого текста, который может получать сенсорные события на себя. Я
попробовал переопределить "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;
}
}
731   14  

14 ответов:

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

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 touch event

@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" />

после ответа @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"/>

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

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

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

одна проблема, ответы на которую здесь не рассматривались, - это "защищенные кнопки" Android.

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

указывает, следует ли фильтровать прикосновения, когда окно представления скрыто через другое видимое окно. Если установлено значение true, представление не будет получать касается всякий раз, когда тост, диалоговое окно или другое окно появляется над окно просмотра. Обратитесь к {@ссылку для Андроид.вид.Просмотр} безопасность документация для получения более подробной информации.

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

android:filterTouchesWhenObscured="true"

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

РАБОТАЕТ ВСЕГДА НА ВЕРХНЕЙ КНОПКЕ ИЗОБРАЖЕНИЯ

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

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

также это дает сенсорный слушателей из других элементов

кнопки alingments находятся внизу и слева

вы можете ставить alingments но нужно изменение cordinats в сенсорное событие в том случае, если элемент

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

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

попробуйте это. Отлично работает в 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

Он использует разрешение " android.разрешение.SYSTEM_ALERT_WINDOW " полный учебник по этой ссылке:http://androidsrc.net/facebook-chat-like-floating-chat-heads/

вот несколько простых решений, Все, что вам нужно, это раздуть 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;
    }

}

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

  • изменение параметров 2 и 3 в "new WindowManager.Ни"
  • попробуйте другой подход к событию

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

событие движения, которое вы перехватили, хотя и имеет действие как ACTION_OUTSIDE, возвращает 0 в getX и Гети. Это означает, что вы не можете видеть все положение движения на экране, и вы ничего не можете сделать. Я знаю, что док сказал, что он получит x и y, но правда в том, что это не так. Кажется, что это блокировать кейлоггер.

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

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

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

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

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

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

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

при добавлении вида в окно с помощью WindowManager.Ни.TYPE_SYSTEM_OVERLAY, он не получает событие касания

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

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

enter image description here

Comments

    Ничего не найдено.