Creating a system overlay window (always on top)

前端 未结 16 947
南方客
南方客 2020-11-21 07:07

I\'m trying to create an always-op-top button/clickable-image which stays on top of all the windows all the time.

The proof of concept is

  • here - Smar
相关标签:
16条回答
  • 2020-11-21 07:34

    Found a library that does just that: https://github.com/recruit-lifestyle/FloatingView

    There's a sample project in the root folder. I ran it and it works as required. The background is clickable - even if it's another app.

    0 讨论(0)
  • 2020-11-21 07:35

    Following @Sam Lu's answer, Indeed Android 4.x blocks certain types from listening to outside touch events, but some types, such as TYPE_SYSTEM_ALERT, still do the job.

    Example

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

    Permissions

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    
    0 讨论(0)
  • 2020-11-21 07:38

    Try this. Works fine in ICS. If You want to stop service simply click the notification generated in statusbar.

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

    UPDATE

    Sample here

    To create an overlay view, when setting up the LayoutParams DON'T set the type to TYPE_SYSTEM_OVERLAY.

    Instead set it to TYPE_PHONE.
    
    Use the following flags:
    
    FLAG_NOT_TOUCH_MODAL
    
    FLAG_WATCH_OUTSIDE_TOUCH
    
    0 讨论(0)
  • 2020-11-21 07:38

    by using service you can achieve this :

    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;
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题