Floating widgets float over the screen over any app that is currently running.
Here we will make a floating action button that you can drag around the screen to position and do actions on it.
Add Permission
For drawing over the other apps, you need “android.permission.SYSTEM_ALERT_WINDOW” permission.
So add this entry in your manifest.
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Our Manifest will look like this
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="floating_demo.coderzheaven.com.floatingdemo"> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".FloatingService" android:enabled="true" android:exported="false" /> </application> </manifest>
Layout
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="floating_demo.coderzheaven.com.floatingdemo.MainActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:gravity="center" android:text="Floating action Demo\n(coderzheaven.com)" /> <Button android:id="@+id/createBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Create Floating Button" android:layout_centerInParent="true" android:textColor="@android:color/white" android:layout_marginBottom="30dp" android:padding="10dp" android:background="@color/colorAccent" android:layout_alignParentBottom="true"/> </RelativeLayout>
The next layout is shown when the floating button is clicked.
We will name it floating_layout.xml.
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content"> <RelativeLayout android:id="@+id/parentRel" android:layout_width="wrap_content" android:layout_height="wrap_content"> <RelativeLayout android:id="@+id/r1" android:layout_width="wrap_content" android:layout_height="wrap_content"> <ImageView android:id="@+id/mainButton" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentTop="true" android:src="@mipmap/ic_launcher" /> <ImageView android:id="@+id/closeBtn" android:layout_width="30dp" android:layout_height="30dp" android:layout_marginLeft="30dp" android:src="@android:drawable/ic_dialog_info" /> </RelativeLayout> <LinearLayout android:id="@+id/showLin" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="10dp" android:layout_toRightOf="@+id/r1" android:background="@color/colorAccent" android:gravity="center" android:padding="20dp" android:visibility="gone"> <ImageView android:id="@+id/btnInfo" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@android:drawable/ic_dialog_info" /> </LinearLayout> </RelativeLayout> </FrameLayout>
Activity and the Floating Service
MainActivity
package floating_demo.coderzheaven.com.floatingdemo; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Toast; public class MainActivity extends AppCompatActivity { private static final int APP_OVERLAY_PERMISSION = 1000; private Context context; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); context = this; // Asking for permission from user... if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, APP_OVERLAY_PERMISSION); } findViewById(R.id.createBtn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (!(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context))) { // Permission was already granted..starting service for creating the Floating Button UI... startService(new Intent(context, FloatingService.class)); finish(); } } }); findViewById(R.id.createBtn).setVisibility(checkIfOverlayPermissionGranted() ? View.VISIBLE : View.GONE); } Boolean checkIfOverlayPermissionGranted() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Settings.canDrawOverlays(context); } @Override protected void onDestroy() { super.onDestroy(); if (!(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context))) { // Permission was already granted..starting service for creating the Floating Button UI... startService(new Intent(context, FloatingService.class)); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == APP_OVERLAY_PERMISSION) { showMessage(checkIfOverlayPermissionGranted() ? "Overlay Permission Granted :)" : "Overlay Permission Denied :("); findViewById(R.id.createBtn).setVisibility(checkIfOverlayPermissionGranted() ? View.VISIBLE : View.GONE); } else { super.onActivityResult(requestCode, resultCode, data); } } // Shows message to the user... void showMessage(String message) { Toast.makeText(context, message, Toast.LENGTH_LONG).show(); } }
We will use a service to draw the floating button over other apps.
Create a java file named FloatingService.java which extends Service.
package floating_demo.coderzheaven.com.floatingdemo; import android.app.Service; import android.content.Intent; import android.graphics.PixelFormat; import android.os.IBinder; import android.support.annotation.Nullable; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.WindowManager; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Toast; public class FloatingService extends Service implements OnClickListener, View.OnTouchListener { private WindowManager mWindowManager; private View mFloatingView; private ImageView mainButton; private LinearLayout showLin; private ImageView btnInfo; private WindowManager.LayoutParams params; private ImageView btnClose; int initialX = 0; int initialY = 0; float initialTouchX = 0; float initialTouchY = 0; @Nullable @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.floating_layout, null); //Add the view to the window. params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); // Set the position to the top right corner of the screen params.gravity = Gravity.TOP | Gravity.LEFT; params.x = 50; params.y = 50; //Add the view to the window mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE); mWindowManager.addView(mFloatingView, params); mainButton = (ImageView) mFloatingView.findViewById(R.id.mainButton); btnClose = (ImageView) mFloatingView.findViewById(R.id.closeBtn); btnInfo = (ImageView) mFloatingView.findViewById(R.id.btnInfo); showLin = (LinearLayout) mFloatingView.findViewById(R.id.showLin); mainButton.setOnClickListener(this); btnInfo.setOnClickListener(this); btnClose.setOnClickListener(this); //Drag and move floating view using user's touch action. mainButton.setOnTouchListener(this); } @Override public void onClick(View view) { if (view == btnClose) { int vis = (showLin.getVisibility() == View.VISIBLE) ? View.GONE : View.VISIBLE; showLin.setVisibility(vis); } if (view == btnInfo) { Intent intent = new Intent(FloatingService.this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); // Stop the service and Remove the Floating Button when our app opens... stopSelf(); } } @Override public void onDestroy() { super.onDestroy(); if (null != mFloatingView && null != mWindowManager) mWindowManager.removeView(mFloatingView); } // Shows message to the user... void showMessage(String message) { Toast.makeText(this, message, Toast.LENGTH_LONG).show(); } @Override public boolean onTouch(View view, MotionEvent motionEvent) { showLin.setVisibility(View.GONE); switch (motionEvent.getAction()) { case MotionEvent.ACTION_DOWN: //remember the initial position. //initialX = params.x; //initialY = params.y; //get the touch location initialTouchX = motionEvent.getRawX(); initialTouchY = motionEvent.getRawY(); return true; case MotionEvent.ACTION_UP: return true; case MotionEvent.ACTION_MOVE: //Calculate the X and Y coordinates of the view. params.x = (int) (motionEvent.getRawX() - initialTouchX) - initialX; params.y = (int) (motionEvent.getRawY() - initialTouchY) - initialY; //Update the layout with new X & Y coordinate mWindowManager.updateViewLayout(mFloatingView, params); return true; } return false; } }
Source Code
You can download the complete source code from here.