Создание системного оверлея (всегда сверху) - PullRequest
269 голосов
/ 19 декабря 2010

Я пытаюсь создать кнопку с открытым верхом / clickable-image который остается на вершине всех окон все время.

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

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

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

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

public class HUD extends Service {
    HUDView mView;

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

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

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

class HUDView extends ViewGroup {
    private Paint mLoadPaint;

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

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

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

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

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

Ответы [ 15 ]

1 голос
/ 04 сентября 2018

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

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

enter image description here

1 голос
/ 27 февраля 2015

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

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 голос
/ 09 октября 2014

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

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

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

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

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

1 голос
/ 19 декабря 2010

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

  • изменить параметры 2 и 3 в "новом WindowManager.LayoutParams"
  • , попробуйте другой подход к событию
0 голосов
/ 20 мая 2016

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

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

При добавлении представления в окно с WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, это не получает событие касания

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...