This article demonstrates how to add a floating chat head in your android application using the Android studio and XML code.
We all love the chat head or chat bubbles from the popular Facebook Messanger. This provides very handy and easy access to the chat conversation screen no matter which screen you are on. Chat heads are very convenient for multitasking as a user can work and chat at the same time. That means if you are using the calculator app on your phone and if any new message arrives, you can open the conversation and replay the message without switching the app.
- Chat heads are nothing but a floating view that is drawn from other applications. Android system allows applications to draw over other application if the application has android.permission.SYSTEM_ALERT_WINDOW permission.
- We are going to use the background service to add the floating widget into the view hierarchy of the current screen. So, this floating view is always on top of application windows
- To, drag the chat head across the screen we are going to override OnTouchListener() to listen to drag events and change the position of the chat has to on the screen.
Let's Start
Step 1
Create a new project in Android Studio from File >> Project and fill all the necessary details.
Next, go to Gradle Scripts >> build. gradle (Module: app).Select build. gradle, The app Gradle compile the code and build types will appear. Just replace that the following code. To make a Floating Chat header in your layout XML and add the Floating library in your project or you can also Gradle.
Compile Code
- compile 'com.github.andremion:counterfab:1.0.1'
Step 2
Next, go to app >> res >> layout >> activity_main.xml.
Select the activity page. The XML code will appear, Just the following code. Create the layout of the TextView and Button.
Step 3
In this step, go to app >> res >> layout >> Right-Click to New >> Layout Resource file. Select Layout Resource page the dialog box will appear to create a new XML page on the given name.
Create new XML page, Just replace the following code
Step 4
In this step, go to app >> Java >> domain name >> MainActivity.java. Select the main activity page, the java code will appear. I have given the code you can use this code or you can use own code
MainActivity Code
- package com.journaldev.floatingchatheads;
-
- import android.content.Intent;
- import android.net.Uri;
- import android.os.Build;
- import android.provider.Settings;
- import android.support.v7.app.AppCompatActivity;
- import android.os.Bundle;
- import android.view.View;
- import android.widget.Button;
- import android.widget.TextView;
- import android.widget.Toast;
-
- public class MainActivity extends AppCompatActivity {
-
-
- private static final int DRAW_OVER_OTHER_APP_PERMISSION = 123;
- private Button button;
-
- private TextView textView;
-
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- askForSystemOverlayPermission();
-
- button = (Button) findViewById(R.id.button);
- textView = (TextView) findViewById(R.id.textView);
-
-
- int badge_count = getIntent().getIntExtra("badge_count", 0);
-
- textView.setText(badge_count + " messages received previously");
-
- button.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(MainActivity.this)) {
- startService(new Intent(MainActivity.this, FloatingWidgetService.class));
- } else {
- errorToast();
- }
- }
- });
-
- }
-
- private void askForSystemOverlayPermission() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
-
-
-
- Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
- Uri.parse("package:" + getPackageName()));
- startActivityForResult(intent, DRAW_OVER_OTHER_APP_PERMISSION);
- }
- }
-
-
- @Override
- protected void onPause() {
- super.onPause();
-
-
-
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || Settings.canDrawOverlays(this)) {
- startService(new Intent(MainActivity.this, FloatingWidgetService.class).putExtra("activity_background", true));
- finish();
- } else {
- errorToast();
- }
- }
-
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == DRAW_OVER_OTHER_APP_PERMISSION) {
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (!Settings.canDrawOverlays(this)) {
-
- errorToast();
- finish();
- }
- }
- } else {
- super.onActivityResult(requestCode, resultCode, data);
- }
- }
-
- private void errorToast() {
- Toast.makeText(this, "Draw over other app permission not available. Can't start the application without the permission.", Toast.LENGTH_LONG).show();
- }
-
- }
Step 5
In this step, go to app >> Java >> domain name >> Right-Click to add >> New >> Java Class. Select the Java Class new dialog box will appear. Create a new java page, Just replace the following code.
FloatingWidgetService Code
Now create a service called FloatingViewService.java. Whenever you want to display a floating view, start the service using the startService() command. In onCreate() of the service, we will add the layout of the floating view at the top-left corner of the window.
- package com.journaldev.floatingchatheads;
-
- import android.app.Service;
- import android.content.Intent;
- import android.graphics.PixelFormat;
- import android.graphics.Point;
- import android.os.IBinder;
- import android.support.annotation.Nullable;
- import android.view.Display;
- import android.view.Gravity;
- import android.view.LayoutInflater;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.ViewTreeObserver;
- import android.view.WindowManager;
- import android.widget.RelativeLayout;
- import com.andremion.counterfab.CounterFab;
-
- public class FloatingWidgetService extends Service {
-
-
- private WindowManager mWindowManager;
- private View mOverlayView;
- int mWidth;
- CounterFab counterFab;
- boolean activity_background;
-
-
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
-
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
-
- if (intent != null) {
- activity_background = intent.getBooleanExtra("activity_background", false);
-
- }
-
- if (mOverlayView == null) {
-
- mOverlayView = LayoutInflater.from(this).inflate(R.layout.overlay_layout, null);
-
-
- final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_PHONE,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
- PixelFormat.TRANSLUCENT);
-
-
-
- params.gravity = Gravity.TOP | Gravity.LEFT;
- params.x = 0;
- params.y = 100;
-
-
- mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
- mWindowManager.addView(mOverlayView, params);
-
- Display display = mWindowManager.getDefaultDisplay();
- final Point size = new Point();
- display.getSize(size);
-
- counterFab = (CounterFab) mOverlayView.findViewById(R.id.fabHead);
- counterFab.setCount(1);
-
-
- final RelativeLayout layout = (RelativeLayout) mOverlayView.findViewById(R.id.layout);
- ViewTreeObserver vto = layout.getViewTreeObserver();
- vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
- @Override
- public void onGlobalLayout() {
- layout.getViewTreeObserver().removeOnGlobalLayoutListener(this);
- int width = layout.getMeasuredWidth();
-
-
-
- mWidth = size.x - width;
-
- }
- });
-
-
OnTouchListener()
To drag the chat head along with the user’s touch, we have to override OnTouchListener(). Whenever the user touches the chat head, we will record the initial x and y coordinates, and when the user moves the finger, the application will calculate the new X and Y coordinate and move the chat head.
Also, implement click listener to close the chat head by stopping the service when the user clicks on the close icon at the top-right of the chat head
TouchListener Code
- counterFab.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:
-
-
- initialX = params.x;
- initialY = params.y;
-
-
-
- initialTouchX = event.getRawX();
- initialTouchY = event.getRawY();
-
-
- return true;
- case MotionEvent.ACTION_UP:
-
-
- if (activity_background) {
-
- float xDiff = event.getRawX() - initialTouchX;
- float yDiff = event.getRawY() - initialTouchY;
-
- if ((Math.abs(xDiff) < 5) && (Math.abs(yDiff) < 5)) {
- Intent intent = new Intent(FloatingWidgetService.this, MainActivity.class);
- intent.putExtra("badge_count", counterFab.getCount());
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
-
-
- stopSelf();
- }
-
- }
-
- int middle = mWidth / 2;
- float nearestXWall = params.x >= middle ? mWidth : 0;
- params.x = (int) nearestXWall;
-
-
- mWindowManager.updateViewLayout(mOverlayView, params);
-
-
- return true;
- case MotionEvent.ACTION_MOVE:
-
-
- int xDiff = Math.round(event.getRawX() - initialTouchX);
- int yDiff = Math.round(event.getRawY() - initialTouchY);
-
-
-
- params.x = initialX + xDiff;
- params.y = initialY + yDiff;
-
-
- mWindowManager.updateViewLayout(mOverlayView, params);
-
-
- return true;
- }
- return false;
- }
- });
- } else {
-
- counterFab.increase();
-
- }
-
-
- return super.onStartCommand(intent, flags, startId);
-
-
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
-
- setTheme(R.style.AppTheme);
-
-
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- if (mOverlayView != null)
- mWindowManager.removeView(mOverlayView);
- }
-
- }
Step 6
Next, go to app >> manifests >> AndroidManifest.XML, Add alert window permission to the AndroidManifest.XML file. This permission allows an app to create windows, a show on top of all other apps. We'll also add a service named FloatingChatHeader that will be created shortly.
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.journaldev.floatingchatheads">
-
- <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
- <uses-permission android:name="TASKS"/>
-
- <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=".FloatingWidgetService"
- android:enabled="true"
- android:exported="false" />
- </application>
- </manifest>
Step 7
Next, go to Android Studio and Deploy the application, Select Emulator or your Android mobile with USB debugging enabled. Give it a few sec to make installations and set permission
Run the application in your desired emulator (Shift + F10)
Summary
Finally, we have successfully created a Floating Chat head application. Later we will discuss more Android Applications.