{"id":23168585,"url":"https://github.com/dofire/floating-bubble-view","last_synced_at":"2025-04-09T10:08:33.887Z","repository":{"id":42066268,"uuid":"438978844","full_name":"dofire/Floating-Bubble-View","owner":"dofire","description":"🍀an Android library that adds floating views on top of your screen🎨, supports both XML and Jetpack Compose","archived":false,"fork":false,"pushed_at":"2024-03-27T03:33:14.000Z","size":3002,"stargazers_count":228,"open_issues_count":8,"forks_count":36,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-09T10:08:27.929Z","etag":null,"topics":["android-app","android-java","android-kotlin","android-library","android-service","android-ui","android-xml","androidkotlin","bubble","chathead","composable","floating-bubbles","floating-view","floating-window","jetpack-compose","jetpack-compose-library","kotlin-android","kotlin-language"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dofire.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-12-16T12:19:19.000Z","updated_at":"2025-04-08T05:43:06.000Z","dependencies_parsed_at":"2023-11-18T15:29:26.734Z","dependency_job_id":"a66da9a0-43c0-42f1-9786-091711f42165","html_url":"https://github.com/dofire/Floating-Bubble-View","commit_stats":null,"previous_names":["dofire/floating-bubble-view","torrydo/floating-bubble-view"],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dofire%2FFloating-Bubble-View","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dofire%2FFloating-Bubble-View/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dofire%2FFloating-Bubble-View/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dofire%2FFloating-Bubble-View/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dofire","download_url":"https://codeload.github.com/dofire/Floating-Bubble-View/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248018060,"owners_count":21034048,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android-app","android-java","android-kotlin","android-library","android-service","android-ui","android-xml","androidkotlin","bubble","chathead","composable","floating-bubbles","floating-view","floating-window","jetpack-compose","jetpack-compose-library","kotlin-android","kotlin-language"],"created_at":"2024-12-18T03:08:26.594Z","updated_at":"2025-04-09T10:08:33.854Z","avatar_url":"https://github.com/dofire.png","language":"Kotlin","readme":"# 🍀Floating Bubble View\nAn Android library that creates floating bubbles on top of the screen 🎨, supports both XML and 💘 Jetpack Compose\n\n\u003cbr\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n\u003ch6\u003e Like this project? 🥰 Don't forget to show some love by giving a Star⭐ \u003c/h6\u003e\n\n| Bubble |  Custom | \n| :-: | :-: |\n| \u003cimg src=\"https://github.com/TorryDo/assets/blob/main/floating_bubble_view/demo/bubble.gif\" height=\"600\" width=\"272\"\u003e | \u003cimg src=\"https://github.com/TorryDo/assets/blob/main/floating_bubble_view/demo/custom_view.gif\" height=\"600\" width=\"276\"\u003e |\n\n\n[\u003cimg src=\"https://img.shields.io/badge/platform-Android-yellow.svg\" valign=\"middle\"\u003e](https://www.android.com)\n[\u003cimg src=\"https://img.shields.io/badge/API-21%2B-brightgreen.svg?style=flat\" valign=\"middle\"\u003e](https://android-arsenal.com/api?level=21)\n[\u003cimg src=\"https://img.shields.io/maven-central/v/io.github.torrydo/floating-bubble-view\" valign=\"middle\"\u003e]()\n[\u003cimg src=\"https://img.shields.io/badge/License-Apache_2.0-blue.svg\" valign=\"middle\"\u003e](https://www.apache.org/licenses/LICENSE-2.0)\n\n\u003c/div\u003e\n\n\u0026nbsp;\n\n## Variants\n- ### Flutter\n     If you are looking for a Flutter version of this library, check [dash_bubble](https://github.com/moazelsawaf/dash_bubble), a Flutter plugin that allows you to create a floating bubble on the screen. by [Moaz El-sawaf](https://github.com/moazelsawaf).\n\n\n## Table of Contents 📝\n\u003e 1. [Getting started](#getting_started)  \n\u003e 2. [Setup](#setup)\n\u003e 3. [Usage](#usage)\n\u003e 4. [Contribution guide](#contribution_guide)\n\u003e 5. [WIP Note](#note) 🚧\n\u003e 6. [License](#license)\n\n\n\n## I, Getting started 🍕🍔🍟 \u003ca name=\"getting_started\"/\u003e\n\n\u003cdetails\u003e \u003csummary\u003e Ensure your app’s minimum SDK version is 21+ and `mavenCentral()` included\u003c/summary\u003e\n\u003c/br\u003e\n1. Ensure your app’s minimum SDK version is 21+. This is declared in the module-level `build.gradle` file \n\n```gradle\nandroid {\n    defaultConfig {\n        ...\n        minSdk 21\n    }\n```\n\n2. Ensure the `mavenCentral()` repository is declared in the project-level `build.gradle`/`setting.gradle` file:\n\n    \u003cdetails\u003e\u003csummary\u003esettings.gradle\u003c/summary\u003e\n\n    ```gradle\n    pluginManagement {\n        repositories {\n            ...\n            mavenCentral()\n        }\n    }\n    dependencyResolutionManagement {\n        ...\n        repositories {\n            ...\n            mavenCentral()\n        }\n    }\n    ```\n\n    \u003c/details\u003e\n\n    \u003cdetails\u003e\u003csummary\u003ebuild.gradle (project-level) (on old gradle versions)\u003c/summary\u003e\n\n    ```gradle\n        allprojects {\n            repositories {\n                mavenCentral()\n                ...\n            }\n            ...\n        }\n    ```\n\n    \u003c/details\u003e\n\n\n\n\n\u003c/details\u003e\n\n\u003c!-- \u003cbr\u003e --\u003e\n\n\u003cbr\u003e\n\n\nDeclare the dependencies in the module-level `build.gradle` file 🍀 \u003cimg src=\"https://img.shields.io/maven-central/v/io.github.torrydo/floating-bubble-view\" valign=\"middle\"\u003e\n\n```gradle\ndependencies {\n    implementation(\"io.github.torrydo:floating-bubble-view:\u003cLATEST_VERSION\u003e\")\n}\n```\n\u003cbr\u003e\n\n## II, Setup 🚀✈🛰 \u003ca name=\"setup_usage\"/\u003e\n\n### 1, extends `ExpandableBubbleService()` and call `expand()` or `minimize()` 1️⃣ \u003ca name=\"setup\"/\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003cb\u003eJava\u003c/b\u003e\u003c/summary\u003e\n\n```java\nJava docs is not completed yet because the author is (really) busy and (a little) tired 😪\n```\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eKotlin\u003c/b\u003e\u003c/summary\u003e\n\n```kotlin\nclass MyService: ExpandableBubbleService() {\n\n    override fun onCreate() {\n        super.onCreate()\n        minimize()\n    }\n\n   // optional, only required if you want to call minimize()\n   override fun configBubble(): BubbleBuilder? {\n       return ...\n   }\n\n   // optional, only required if you want to call expand()\n   override fun configExpandedBubble(): ExpandedBubbleBuilder? {\n       return ...\n   }\n}\n```\n\n\u003c/details\u003e\n\n\u003c/br\u003e\n\n### 2, add bubble service to the manifest file 2️⃣\n\n\n\n```xml\n\u003capplication\u003e\n     \u003c!-- these two permissions are added by default --\u003e\n     \u003c!-- \u003cuses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\"/\u003e --\u003e\n     \u003c!-- \u003cuses-permission android:name=\"android.permission.FOREGROUND_SERVICE\"/\u003e --\u003e\n\n     \u003c!-- You can find more permissions, use cases here: https://developer.android.com/about/versions/14/changes/fgs-types-required  --\u003e\n     \u003cuses-permission android:name=\"android.permission.FOREGROUND_SERVICE_SPECIAL_USE\" /\u003e\n     \n     \u003cservice\n         android:name=\"\u003cYOUR_PACKAGE\u003e.MyService\"\n         android:foregroundServiceType=\"specialUse\"\n         \u003e\n         \u003cproperty android:name=\"android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE\" android:value=\"foo\"/\u003e  \u003c!-- optional --\u003e\n     \u003c/service\u003e\n\n\u003c/application\u003e\n```\n\n\u003cdetails\u003e\u003csummary\u003eAndroid 13 and earlier\u003c/summary\u003e\n\n```xml\n    \u003c!-- these two permissions are added by default --\u003e\n    \u003c!-- \u003cuses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\"/\u003e --\u003e\n    \u003c!-- \u003cuses-permission android:name=\"android.permission.FOREGROUND_SERVICE\"/\u003e --\u003e\n\n    \u003capplication\u003e\n        ...\n        \u003cservice android:name=\"\u003cYOUR_PACKAGE\u003e.MyService\" /\u003e\n\n    \u003c/application\u003e\n```\n     \n\u003c/details\u003e\n\n\n\u003c/br\u003e\n\n### 3, start bubble service and enjoy 3️⃣ 🎉🍀\n\u003e Make sure \"display over other apps\" permission is granted, otherwise the app will crash ⚠❗💥\n\n\u003cdetails\u003e\u003csummary\u003e\u003cb\u003eJava\u003c/b\u003e\u003c/summary\u003e\n\n```java\n    Intent intent = new Intent(context, MyService.class);\n    \n    ContextCompat.startForegroundService(this, intent);\n    // or\n    // startService(intent);           // for android version lower than 8.0 (android O)\n    // startForegroundService(intent); // for android 8.0 and higher\n```\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003e\u003cb\u003eKotlin\u003c/b\u003e\u003c/summary\u003e\n\n```kotlin\n    val intent = Intent(context, MyService::class.java)\n    \n    ContextCompat.startForegroundService(this, intent)\n    // or\n    // startService(intent)           // for android version lower than 8.0 (android O)\n    // startForegroundService(intent) // for android 8.0 and higher\n```\n\n\u003c/details\u003e\n\n\n\n\u003c/br\u003e\n\n## III, Usage 🔥 \u003ca name=\"usage\"/\u003e\n\n### 1, `configBubble()` and `configExpandedBubble()`\n\n\u003cdetails\u003e\u003csummary\u003eJava\u003c/summary\u003e\n\n```java\npublic class MyServiceJava extends ExpandableBubbleService {\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        minimize();\n    }\n\n    @Nullable\n    @Override\n    public BubbleBuilder configBubble() {\n        View imgView = ViewHelper.fromDrawable(this, R.drawable.ic_rounded_blue_diamond, 60, 60);\n        imgView.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View view) {\n                expand();\n            }\n        });\n        return new BubbleBuilder(this)\n                .bubbleView(imgView)\n                .bubbleStyle(R.style.default_bubble_style)\n                .bubbleDraggable(true)\n                .forceDragging(true)\n                .closeBubbleView(ViewHelper.fromDrawable(this, R.drawable.ic_close_bubble))\n                .closeBubbleStyle(R.style.default_close_bubble_style)\n                .distanceToClose(100)\n                .triggerClickablePerimeterPx(5f)\n                .closeBehavior(CloseBubbleBehavior.FIXED_CLOSE_BUBBLE)\n                .startLocation(100, 100)\n                .enableAnimateToEdge(true)\n                .bottomBackground(false)\n                .addFloatingBubbleListener(new FloatingBubbleListener() {\n                    @Override\n                    public void onFingerDown(float x, float y) {}\n                    @Override\n                    public void onFingerUp(float x, float y) {}\n                    @Override\n                    public void onFingerMove(float x, float y) {}\n                })\n                ;\n                \n    }\n\n    @Nullable\n    @Override\n    public ExpandedBubbleBuilder configExpandedBubble() {\n        View expandedView = LayoutInflater.from(this).inflate(R.layout.layout_view_test, null);\n\n        expandedView.findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View view) {\n                minimize();\n            }\n        });\n        return new ExpandedBubbleBuilder(this)\n                .expandedView(expandedView)\n                .startLocation(0, 0)\n                .draggable(true)\n                .style(R.style.default_bubble_style)\n                .fillMaxWidth(true)\n                .enableAnimateToEdge(true)\n                .dimAmount(0.5f);\n    }\n}\n```\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003eKotlin\u003c/summary\u003e\n\n```kotlin\nclass MyServiceKt : ExpandableBubbleService() {\n\n    override fun onCreate() {\n        super.onCreate()\n        minimize()\n    }\n\n    override fun configBubble(): BubbleBuilder? {\n        val imgView = ViewHelper.fromDrawable(this, R.drawable.ic_rounded_blue_diamond, 60, 60)\n        imgView.setOnClickListener {\n            expand()\n        }\n\n        return BubbleBuilder(this)\n            \n            // set bubble view\n            .bubbleView(imgView)\n            \n            // or our sweetie, Jetpack Compose\n            .bubbleCompose {\n                BubbleCompose()\n            }\n            \n            // set style for the bubble, fade animation by default\n            .bubbleStyle(null)\n            \n            // set start location for the bubble, (x=0, y=0) is the top-left\n            .startLocation(100, 100)    // in dp\n            .startLocationPx(100, 100)  // in px\n            \n            // enable auto animate bubble to the left/right side when release, true by default\n            .enableAnimateToEdge(true)\n            \n            // set close-bubble view\n            .closeBubbleView(ViewHelper.fromDrawable(this, R.drawable.ic_close_bubble, 60, 60))\n            \n            // set style for close-bubble, null by default\n            .closeBubbleStyle(null)\n            \n            // DYNAMIC_CLOSE_BUBBLE: close-bubble moving based on the bubble's location\n            // FIXED_CLOSE_BUBBLE (default): bubble will automatically move to the close-bubble when it reaches the closable-area\n            .closeBehavior(CloseBubbleBehavior.DYNAMIC_CLOSE_BUBBLE)\n            \n            // the more value (dp), the larger closeable-area\n            .distanceToClose(100)\n            \n            // enable bottom background, false by default\n            .bottomBackground(true)\n            \n            .addFloatingBubbleListener(object : FloatingBubbleListener {\n                override fun onFingerMove(x: Float, y: Float) {} // The location of the finger on the screen which triggers the movement of the bubble.\n                override fun onFingerUp(x: Float, y: Float) {}   // ..., when finger release from bubble\n                override fun onFingerDown(x: Float, y: Float) {} // ..., when finger tap the bubble\n            })\n\n            // set the clickable perimeter of the bubble in pixels (default = 5f)\n            .triggerClickablePerimeterPx(5f)\n\n    }\n\n    override fun configExpandedBubble(): ExpandedBubbleBuilder? {\n\n        val expandedView = LayoutInflater.from(this).inflate(R.layout.layout_view_test, null)\n        expandedView.findViewById\u003cView\u003e(R.id.btn).setOnClickListener {\n            minimize()\n        }\n\n        return ExpandedBubbleBuilder(this)\n            .expandedView(expandedView)\n            .expandedCompose { \n                ExpandedCompose()\n            }\n            // handle key code\n            .onDispatchKeyEvent {\n                if(it.keyCode == KeyEvent.KEYCODE_BACK){\n                    minimize()\n                }\n                null\n            }\n            // set start location in dp\n            .startLocation(0, 0)\n            // allow expanded bubble can be draggable or not\n            .draggable(true)\n            // fade animation by default\n            .style(null)\n            // \n            .fillMaxWidth(true)\n            // animate to the left/right side when release, trfalseue by default \n            .enableAnimateToEdge(true)\n            // set background dimmer\n            .dimAmount(0.6f)\n    }\n}\n```\n\n\u003c/details\u003e\n\n\u003cbr\u003e\n\n### 2, Override default `Notification`\n\u003cdetails\u003e\u003csummary\u003eJava\u003c/summary\u003e\n\n```java\npublic class MyService extends ExpandableBubbleService {\n    ...\n    @Override\n    public void startNotificationForeground() {\n        startForeground(...);\n\n        // or you can use NotificationHelper class\n        // val noti = NotificationHelper(this)\n        // noti.createNotificationChannel()\n        // startForeground(noti.notificationId, noti.defaultNotification())\n    }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails open\u003e\u003csummary\u003eKotlin\u003c/summary\u003e\n\n```kotlin\nclass MyService : FloatingBubbleService() {\n    ...\n    // optional, of course\n    override fun startNotificationForeground() {\n        startForeground(...)\n\n        // or you can use NotificationHelper class\n        // val noti = NotificationHelper(this)\n        // noti.createNotificationChannel()\n        // startForeground(noti.notificationId, noti.defaultNotification())\n    }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eNotice since Android 13 ⚠ \u003c/summary\u003e\n\u003cbr/\u003e\n\nStarting in Android 13 (API level 33), notifications are only visible if the \"POST_NOTIFICATIONS\" permission is granted.\u003cbr/\u003e\n\n\u003e The service will run normally even if the notification is not visible. 🍀\n\n\u003e You still need to initialize the notification before showing any view.\n\n\u003c/details\u003e\n\n\u003cbr\u003e\n\n### 3, Methods in `ExpandableBubbleService`\n\n| Name | Description |\n| :- | :- |\n| `removeAll()` | remove all bubbles |\n| `expand()` | show expanded-bubble |\n| `minimize()` | show bubble |\n| `enableBubbleDragging()` | enable bubble dragging or not |\n| `enableExpandedBubbleDragging()` | enable expanded-bubble dragging or not |\n| `animateBubbleToEdge()` | animate bubble to edge of the screen |\n| `animateExpandedBubbleToEdge()` | animate expanded-bubble to edge of the screen |\n\n\u003cbr\u003e\n\n### 4, Helper Class\n- ViewHelper()\n     - fromBitmap(context, bitmap): View\n     - fromBitmap(context, bitmap, widthDp, heightDp): View\n     - fromDrawable(context, drawableRes): View\n     - fromDrawable(context, drawableRes, widthDp, heightDp)\n\n- NotificationHelper(context, channelId, channelName, notificationId)\n     - notify(Notification): update notification based on notificationId\n     - createNotificationChannel(): create notification channel from `android 8` and above\n     - defaultNotification(): return default notification\n\n\u003c/br\u003e\n\n## IV, Contribution Guide 👏  \u003ca name=\"contribution_guide\"\u003e\n\nContributions are welcome! 🙌\n\n- If you come across a bug or have an idea for a new feature, please let us know by creating an [Issue](https://github.com/TorryDo/Floating-Bubble-View/issues) 🐛💡\n- If you're interested in taking on an [open issue](https://github.com/TorryDo/Floating-Bubble-View/issues), please comment on it so others are aware 😊\n- If you've already fixed a bug or implemented a feature, feel free to submit a [Pull request](https://github.com/TorryDo/Floating-Bubble-View/pulls) 🚀\n- Having questions, ideas, or feedback? Don't worry, I gotchu. Simply open a [Discussion](https://github.com/TorryDo/Floating-Bubble-View/discussions) 🔊\n- Find this project useful? 🥰 Don't forget to show some love by giving a star ⭐\n\nThank you! 💖\n\n\u003cbr\u003e\n\n## V, Work in Progress 🚧 \u003ca name=\"note\"\u003e\nThis library is still under heavy development. There is still a lot of code cleanup to do, so expect breaking API changes over time.\n\nPlease refer to the following page to check out the change-log: [Releases](https://github.com/TorryDo/Floating-Bubble-View/releases)\n\nEverything's gonna be ok! 🍀\n\n\u003cbr\u003e\n\n## VI, License \u003ca name=\"license\"/\u003e\n\n```\n\n    Copyright 2022 TorryDo\n\n    Licensed under the Apache License, Version 2.0 (the \"License\");\n    you may not use this file except in compliance with the License.\n    You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n    Unless required by applicable law or agreed to in writing, software\n    distributed under the License is distributed on an \"AS IS\" BASIS,\n    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n    See the License for the specific language governing permissions and\n    limitations under the License.\n\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdofire%2Ffloating-bubble-view","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdofire%2Ffloating-bubble-view","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdofire%2Ffloating-bubble-view/lists"}