Android displaying floating widget overlay not working

android floating overlay
androidhive floating widget
movable floating action button android
android overlay example
android floating action button overlay
cordova floating widget
floating view android github
floating video player android example

I want my my app to display a floating bubble notification as in facebook messenger. Following https://www.androidhive.info/2016/11/android-floating-widget-like-facebook-chat-head/ below is the service I wrote.

import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class BubbleNotifyService extends Service {

    private WindowManager windowManager;
    private View BubbleView;
    private TextView bubbleTitle, bubbleData;

    public BubbleNotifyService() {
    }

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

    @SuppressLint({"RtlHardcoded", "InflateParams"})
    @Override
    public void onCreate() {
        super.onCreate();
        //android.os.Debug.waitForDebugger();

        setTheme(R.style.AppTheme);

        BubbleView =
                LayoutInflater.from(this).inflate(R.layout.floating_bubble, null);

        final WindowManager.LayoutParams params;

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT
        );
    } else {
        params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.TYPE_PHONE,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE ,
                PixelFormat.TRANSLUCENT
        );
    }

        if (BubbleView == null) {
            Log.d("Bubble", "BubbleView is null.");
        }

        params.gravity = Gravity.TOP | Gravity.LEFT;
        params.x = 0;
        params.y = 100;

        windowManager =
                (WindowManager) getSystemService(WINDOW_SERVICE);

        if (windowManager != null) {
            Log.d("Bubble", "added bubble to view.");
            windowManager.addView(BubbleView, params);
        } else {
            Log.d("Bubble", "windowManager is null");
        }

        final View collapsedView =
                BubbleView.findViewById(R.id.collapsed_view);
        final View expandedView =
                BubbleView.findViewById(R.id.expanded_view);

        expandedView.setVisibility(View.GONE);
        collapsedView.setVisibility(View.VISIBLE);


        ImageView close_collapsed = BubbleView.findViewById(R.id.collaspsed_cancel);
        ImageView close_expanded = BubbleView.findViewById(R.id.expanded_cancel);
        Button open_act_btn = BubbleView.findViewById(R.id.open_full_btn);
        bubbleTitle = BubbleView.findViewById(R.id.bubble_title);
        bubbleMeaning = BubbleView.findViewById(R.id.bubble_data);

        close_collapsed.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                stopSelf();
            }
        });

        close_expanded.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                collapsedView.setVisibility(View.VISIBLE);
                expandedView.setVisibility(View.GONE);
            }
        });

        open_act_btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //TODO new Activity
            }
        });

        BubbleView.findViewById(R.id.bubble_root).setOnTouchListener(new View.OnTouchListener() {

            private int initialX;
            private int initialY;
            private float initialTouchX;
            private float initialTouchY;

            @SuppressLint("ClickableViewAccessibility")
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {

                switch (motionEvent.getAction()) {

                    case MotionEvent.ACTION_DOWN:
                        initialX = params.x;
                        initialY = params.y;

                        initialTouchX = motionEvent.getRawX();
                        initialTouchY = motionEvent.getRawY();
                        return true;

                    case MotionEvent.ACTION_UP:
                        int Xdiff = (int) (motionEvent.getRawX() - initialTouchX);
                        int Ydiff = (int) (motionEvent.getRawY() - initialTouchY);

                        if (Xdiff < 10 && Ydiff < 10) {
                            if (isViewCollapsed()) {
                                collapsedView.setVisibility(View.GONE);
                                expandedView.setVisibility(View.VISIBLE);
                            }
                        }
                        return true;

                    case MotionEvent.ACTION_MOVE:
                        params.x =
                                initialX + (int) (motionEvent.getRawX() - initialTouchX);
                        params.y =
                                initialY + (int) (motionEvent.getRawY() - initialTouchY);

                        windowManager.updateViewLayout(BubbleView, params);
                        return true;
                }
                return false;
            }
        });

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);

        String title = intent.getStringExtra(IntentKeys.BUBBLE_DATA_TITLE);
        String data = intent.getStringExtra(IntentKeys.BUBBLE_DATA);

        bubbleTitle.setText(title);
        bubbleData.setText(data);

        return START_NOT_STICKY;
    }

    private boolean isViewCollapsed() {
        return BubbleView == null ||
                BubbleView.findViewById(R.id.collapsed_view).getVisibility() == View.VISIBLE;
    }


    @Override
    public void onDestroy() {
        super.onDestroy();

        if (BubbleView != null) {
            windowManager.removeView(BubbleView);
        }
    }
}

BubbleNotifyService is called from another service that receives notification as:

Intent intent = new Intent(context, BubbleNotifyService.class);
                intent.putExtra(IntentKeys.BUBBLE_DATA_TITLE, Results.getWord());
                intent.putExtra(IntentKeys.BUBBLE_DATA, Results.getData());
                context.startService(intent);

All data from the intent is passed to BubbleNotifyService. The service is running as a separate process as specified in manifest android:process=":BubbleResult", But the service does not display any overlay. Draw over other app permission is granted to the app.

Layout for bubble(floating_bubble.xml)

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/bubble_frame"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <android.support.constraint.ConstraintLayout
        android:id="@+id/bubble_root"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">


        <android.support.constraint.ConstraintLayout
            android:id="@+id/collapsed_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="visible">

            <ImageView
                android:id="@+id/collapsed_icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:srcCompat="@mipmap/ic_launcher"
                tools:ignore="ContentDescription" />

            <ImageView
                android:id="@+id/collaspsed_cancel"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintStart_toEndOf="@+id/collapsed_icon"
                app:layout_constraintTop_toTopOf="parent"
                app:srcCompat="@drawable/ic_action_cancel"
                tools:ignore="ContentDescription" />

        </android.support.constraint.ConstraintLayout>

        <android.support.v7.widget.CardView
            android:id="@+id/expanded_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:visibility="visible"
            app:cardCornerRadius="5dp"
            app:cardElevation="10dp"
            app:cardUseCompatPadding="true"
            app:contentPadding="5dp">

            <android.support.constraint.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <TextView
                    android:id="@+id/bubble_title"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="8dp"
                    android:textSize="24sp"
                    android:textStyle="bold"
                    app:layout_constraintEnd_toStartOf="@id/expanded_cancel"
                    app:layout_constraintHorizontal_bias="0.0"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    tools:text="@string/result_card_title" />

                <TextView
                    android:id="@+id/bubble_data"
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:textSize="18sp"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@id/bubble_title"
                    tools:text="@string/result_card_data" />

                <ImageView
                    android:id="@+id/expanded_cancel"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toEndOf="@id/bubble_title"
                    app:srcCompat="@drawable/ic_action_cancel"
                    tools:ignore="ContentDescription" />

                <Button
                    android:id="@+id/open_full_btn"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginEnd="8dp"
                    android:layout_marginTop="8dp"
                    android:text="@string/result_card_see_more"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/bubble_data" />


            </android.support.constraint.ConstraintLayout>
        </android.support.v7.widget.CardView>

    </android.support.constraint.ConstraintLayout>


</FrameLayout>

Please care to explain the reason for downvoting if you are downvoting this.

Tested both Your code and mentioned blog post's code. The problem seems to be because You have used ConstraintLayout and CardView in Your layout.

For widget behavior, these view types are not supported. When we add view directly to the system window they behave likes RemoteViews. As soon as You change ConstraintLayout and CardView, Your layout becomes visible and operable.

Android Floating Widget Like Messenger Bubbles, Active 1 year, 5 months ago. Viewed 3k times. 7. 2. I want my my app to display a floating bubble notification as in facebook messenger. Following  Now you can uncage your widgets from the home screen. Overlays, a new app for Android 4.0 and higher, can make your app widgets appear as a layer on top of the UI, even while other apps are open.

Here is my working code. You will start this Service when you need to show floating view.

FloatingService.class

import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Build;
import android.os.IBinder;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.Toast;

public class FloatingService extends Service {

    private WindowManager mWindowManager;
    private View mFloatingView;

    public FloatingService() {
    }

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

    @Override
    public void onCreate() {
        super.onCreate();
        //Inflate the floating view layout we created
        mFloatingView = LayoutInflater.from(this).inflate(R.layout.layout_floating_widget, null);
        int LAYOUT_FLAG;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
        } else {
            LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
        }
        //Add the view to the window.
        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                WindowManager.LayoutParams.WRAP_CONTENT,
                WindowManager.LayoutParams.WRAP_CONTENT,
                LAYOUT_FLAG,
                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
                PixelFormat.TRANSLUCENT);

        //Specify the view position
        params.gravity = Gravity.TOP | Gravity.LEFT;        //Initially view will be added to top-left corner
        params.x = 0;
        params.y = 100;

        //Add the view to the window
        mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
        mWindowManager.addView(mFloatingView, params);

        //The root element of the collapsed view layout
        final View collapsedView = mFloatingView.findViewById(R.id.collapse_view);
        //The root element of the expanded view layout
        final View expandedView = mFloatingView.findViewById(R.id.expanded_container);


        //Set the close button
        ImageView closeButtonCollapsed = (ImageView) mFloatingView.findViewById(R.id.close_btn);
        closeButtonCollapsed.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //close the service and remove the from from the window
                stopSelf();
            }
        });

        //Set the view while floating view is expanded.
        //Set the play button.
        ImageView playButton = (ImageView) mFloatingView.findViewById(R.id.play_btn);
        playButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(FloatingService.this, "Playing the song.", Toast.LENGTH_LONG).show();
            }
        });

        //Set the next button.
        ImageView nextButton = (ImageView) mFloatingView.findViewById(R.id.next_btn);
        nextButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(FloatingService.this, "Playing next song.", Toast.LENGTH_LONG).show();
            }
        });

        //Set the pause button.
        ImageView prevButton = (ImageView) mFloatingView.findViewById(R.id.prev_btn);
        prevButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(FloatingService.this, "Playing previous song.", Toast.LENGTH_LONG).show();
            }
        });

        //Set the close button
        ImageView closeButton = (ImageView) mFloatingView.findViewById(R.id.close_button);
        closeButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                collapsedView.setVisibility(View.VISIBLE);
                expandedView.setVisibility(View.GONE);
            }
        });

        //Open the application on thi button click
        ImageView openButton = (ImageView) mFloatingView.findViewById(R.id.open_button);
        openButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //Open the application  click.
                Intent intent = new Intent(FloatingService.this, MainActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);

                //close the service and remove view from the view hierarchy
                stopSelf();
            }
        });

        //Drag and move floating view using user's touch action.
        mFloatingView.findViewById(R.id.root_container).setOnTouchListener(new View.OnTouchListener() {
            private int initialX;
            private int initialY;
            private float initialTouchX;
            private float initialTouchY;

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:

                        //remember the initial position.
                        initialX = params.x;
                        initialY = params.y;

                        //get the touch location
                        initialTouchX = event.getRawX();
                        initialTouchY = event.getRawY();
                        return true;
                    case MotionEvent.ACTION_UP:
                        int Xdiff = (int) (event.getRawX() - initialTouchX);
                        int Ydiff = (int) (event.getRawY() - initialTouchY);

                        //The check for Xdiff <10 && YDiff< 10 because sometime elements moves a little while clicking.
                        //So that is click event.
                        if (Xdiff < 10 && Ydiff < 10) {
                            if (isViewCollapsed()) {
                                //When user clicks on the image view of the collapsed layout,
                                //visibility of the collapsed layout will be changed to "View.GONE"
                                //and expanded view will become visible.
                                collapsedView.setVisibility(View.GONE);
                                expandedView.setVisibility(View.VISIBLE);
                            }
                        }
                        return true;
                    case MotionEvent.ACTION_MOVE:
                        //Calculate the X and Y coordinates of the view.
                        params.x = initialX + (int) (event.getRawX() - initialTouchX);
                        params.y = initialY + (int) (event.getRawY() - initialTouchY);

                        //Update the layout with new X & Y coordinate
                        mWindowManager.updateViewLayout(mFloatingView, params);
                        return true;
                }
                return false;
            }
        });
    }

    /**
     * Detect if the floating view is collapsed or expanded.
     *
     * @return true if the floating view is collapsed.
     */
    private boolean isViewCollapsed() {
        return mFloatingView == null || mFloatingView.findViewById(R.id.collapse_view).getVisibility() == View.VISIBLE;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mFloatingView != null) mWindowManager.removeView(mFloatingView);
    }
}

Then add

  <service
            android:name="yourpakcage.FloatingService"
            android:enabled="true"
            android:exported="false"/>

layout_floating_widget.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <!--Root container-->
    <RelativeLayout
        android:id="@+id/root_container"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        tools:ignore="UselessParent">

        <!--View while view is collapsed-->
        <RelativeLayout
            android:id="@+id/collapse_view"
            android:layout_width="wrap_content"
            android:visibility="visible"
            android:layout_height="wrap_content"
            android:orientation="vertical">

            <!--Icon of floating widget -->
            <ImageView
                android:id="@+id/collapsed_iv"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_marginTop="8dp"
                android:src="@drawable/ic_android_circle"
                tools:ignore="ContentDescription"/>

            <!--Close button-->
            <ImageView
                android:id="@+id/close_btn"
                android:layout_width="20dp"
                android:layout_height="20dp"
                android:layout_marginLeft="40dp"
                android:src="@drawable/ic_close"
                tools:ignore="ContentDescription"/>
        </RelativeLayout>

        <!--View while view is expanded-->
        <LinearLayout
            android:id="@+id/expanded_container"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:background="#F8BBD0"
            android:visibility="gone"
            android:orientation="horizontal"
            android:padding="8dp">

            <!--Album image for the song currently playing.-->
            <ImageView
                android:layout_width="80dp"
                android:layout_height="80dp"
                android:src="@drawable/music_player"
                tools:ignore="ContentDescription"/>

            <!--Previous button-->
            <ImageView
                android:id="@+id/prev_btn"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="20dp"
                android:src="@mipmap/ic_previous"
                tools:ignore="ContentDescription"/>

            <!--Play button-->
            <ImageView
                android:id="@+id/play_btn"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:src="@mipmap/ic_play"
                tools:ignore="ContentDescription"/>

            <!--Next button-->
            <ImageView
                android:id="@+id/next_btn"
                android:layout_width="30dp"
                android:layout_height="30dp"
                android:layout_gravity="center_vertical"
                android:layout_marginLeft="10dp"
                android:src="@mipmap/ic_play_next"
                tools:ignore="ContentDescription"/>

            <RelativeLayout
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <ImageView
                    android:id="@+id/close_button"
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:src="@drawable/ic_close"/>

                <ImageView
                    android:id="@+id/open_button"
                    android:layout_width="20dp"
                    android:layout_height="20dp"
                    android:layout_alignParentBottom="true"
                    android:src="@drawable/ic_open"/>
            </RelativeLayout>
        </LinearLayout>
    </RelativeLayout>
</FrameLayout>

Please add dummy drawables and strings.

To show your floating view.

startService(new Intent(passContext, FloatingViewService.class));

Android displaying floating widget overlay not working, To display android floating widget we need to start a background service and add Display a floating action button as the overlay view when the We need to detect whether the activity is running in the background or not. A very common example of Android Floating Widget can be seen with the Facebook Messenger App and I am sure many of you are already using messenger. So if you want to create a widget like that then, that is what we will be creating in this Android Floating Widget Tutorial.

Unfortunately the guide you've been following is outdated. You're trying to start a service while your app is in the background which results in an IllegalArgumentException because of the Background Execution Limits introduced in Android Oreo. A migration guide is included at the bottom of the link.

How to Make Android Floating Widget For Multiple Views Float On , Learn how to use and implement android floating widget in an android app The floating widget in Android basically helps in multitasking as a user can work on other makeText(this, "Draw over other app permission not enable. How to Implement Android Toolbar to Display Different Activity Navigation. Floating Widget is a very useful part of a android application. Floating widget can display over apps menu and mobile phone screen and user can itself close if or open it. So in this tutorial we would going to create an Floating Widget which can show our apps and can be movable by user finger.

Android Floating Widget Tutorial, Learn creating Android Floating Widget. An android floating widget becomes very handy on multitasking. Android Floating Widget Tutorial – Display Widget Over Apps And I will try to solve your problems. Thank You  Display a floating action button as the overlay view when the application is in the background. We’ll be using CounterFab library. Dragging the widget anywhere on the screen. Letting the widget position itself along the nearest edge of the screen (instead of keeping it hanging in the middle).

Floating Widget In Android, Floating widgets are nothing but simple action buttons that perform some action and always overlay, can float anywhere on the entire screen. Uber and Ola driver applications also have these floating widget buttons that can Location settings are not satisfied, but this can be fixed; // by showing the user a  Floating widgets are the views that float over the screen. This view will remain floating on the screen no matter whichever screen you are in. They are very convenient for multitasking as a user can work on other application and control your application for the same time. That means if you are in the calculator

Android Floating Widget like Facebook Chat Head, They are very convenient for multitasking as a user can work on other (To keep this article focused around floating widget, we will not look into Whenever you want to display a floating view, start the service using There is any idea to create a floating button which will be overlay only home screen? Definitely one of the best new apps of 2013, Overlays allows you to use widgets & shortcuts in all kinds of cool and creative ways. With Tasker integration the possibilities are endless. Overlays

Comments
  • 1. Which device are you testing? 2. Does this code crash? (post error log then).
  • @Khemraj I have tested this on physical moto g5 & pixel 2 emulator. The app does not crash . The service runs successfully and a process is created for same but the overlay is not displayed.
  • I post my working code for you.
  • find out error is in java or layout this way instead of using layout: BubbleView = new TextView(this); BubbleView.setText("Some Text for Test") if problem is solved your layout may have a problem or has no content to show for example text in textView or image in ImageView or layout width is 0
  • what's the alternative if I want card like views in the floating widget??
  • You can play with shadow. Have a simple RelativeLayout with the background set as shadow drawable. It will give an exposure like card view. Shadow and the proper background color is the key.
  • I could not check difference, i also followed same tutorial before some days, and this above is my working code.
  • no such exception is thrown as seen in logcat. Also I am running this app in android 7.
  • Well in that case I'm afraid you'll have 2 problems to solve. Even if you fix the problem in your current code for Android 7 it won't run on Android 8 or higher.
  • I added checks for android 8 to use startForegroundService(). One problem down.