diff --git a/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/Extensions.kt b/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/Extensions.kt
index 2e5d1eb..55501d6 100644
--- a/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/Extensions.kt
+++ b/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/Extensions.kt
@@ -27,8 +27,8 @@ internal fun View.getXYPointOnScreen(): Point {
return Point(arr[0], arr[1])
}
-internal val Int.toDp: Int get() = (this / getSystem().displayMetrics.density).toInt()
-internal val Int.toPx: Int get() = (this * getSystem().displayMetrics.density).toInt()
+internal fun Int.toDp(): Int = (this / getSystem().displayMetrics.density).toInt()
+internal fun Int.toPx(): Int = (this * getSystem().displayMetrics.density).toInt()
inline fun View.afterMeasured(crossinline afterMeasuredWork: () -> Unit) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
diff --git a/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingBubble.kt b/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingBubble.kt
index 09f1619..881e46f 100644
--- a/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingBubble.kt
+++ b/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingBubble.kt
@@ -5,7 +5,6 @@ import android.graphics.Bitmap
import android.graphics.Point
import android.util.Size
import android.view.View
-import androidx.annotation.Discouraged
import androidx.annotation.DrawableRes
import androidx.annotation.StyleRes
import androidx.core.content.ContextCompat
@@ -90,8 +89,8 @@ internal constructor(
}
internal fun tryShowCloseBubbleAndBackground() {
- bottomBackground?.show()
closeBubbleView?.show()
+ bottomBackground?.show()
}
internal fun tryRemoveCloseBubbleAndBackground() {
@@ -201,7 +200,6 @@ internal constructor(
// config
internal var startPoint = Point(0, 0)
- internal var elevation = 0
internal var opacity = 1f
internal var isCloseBubbleEnabled = true
internal var isAnimateToEdgeEnabled = true
@@ -228,7 +226,7 @@ internal constructor(
*
* @param dp distance between bubble and close-bubble
* */
- fun closablePerimeter(dp: Int): Builder {
+ fun distanceToClose(dp: Int): Builder {
this.closablePerimeterDp = dp
return this
}
@@ -242,7 +240,7 @@ internal constructor(
}
/**
- * @param enabled animate bubble to the left/right side of the screen
+ * @param enabled animate the bubble to the left/right side of the screen when finger is released, true by default
* */
fun enableAnimateToEdge(enabled: Boolean): Builder {
isAnimateToEdgeEnabled = enabled
@@ -275,7 +273,7 @@ internal constructor(
* set drawable to bubble width given width and height in dp
* */
fun bubble(@DrawableRes drawable: Int, widthDp: Int, heightDp: Int): Builder {
- bubbleSizePx = Size(widthDp.toPx, heightDp.toPx)
+ bubbleSizePx = Size(widthDp.toPx(), heightDp.toPx())
return bubble(drawable)
}
@@ -291,7 +289,7 @@ internal constructor(
* set bitmap to bubble width given width and height in dp
* */
fun bubble(bitmap: Bitmap, widthDp: Int, heightDp: Int): Builder {
- bubbleSizePx = Size(widthDp.toPx, heightDp.toPx)
+ bubbleSizePx = Size(widthDp.toPx(), heightDp.toPx())
return bubble(bitmap)
}
@@ -321,7 +319,7 @@ internal constructor(
* set drawable to close-bubble with given width and height in dp
* */
fun closeBubble(@DrawableRes drawable: Int, widthDp: Int, heightDp: Int): Builder {
- this.closeBubbleSizePx = Size(widthDp.toPx, heightDp.toPx)
+ this.closeBubbleSizePx = Size(widthDp.toPx(), heightDp.toPx())
return closeBubble(drawable)
}
@@ -380,29 +378,37 @@ internal constructor(
}
/**
- * examples: x=0, y=0 show bubble on the top-left corner of the screen.
+ * examples: x=0, y=0 show the bubble on the top-left corner of the screen.
*
- * you can set x/y as negative value, but the bubble will be outside the screen.
+ * you can set x/y as a negative values, but the bubble will be outside the screen.
*
- * @param x 0 ... screenWidth (px).
- * @param y 0 ... screenHeight (px).
+ * @param x 0 ... screenWidth (dp).
+ * @param y 0 ... screenHeight (dp).
* */
fun startLocation(x: Int, y: Int): Builder {
- startPoint.x = x
- startPoint.y = y
+ startPoint.x = x.toPx()
+ startPoint.y = y.toPx()
return this
}
- // not exposed to the outside packages because of being developed
- internal fun elevation(dp: Int): Builder {
- elevation = dp
+ /**
+ * examples: x=0, y=0 show the bubble on the top-left corner of the screen.
+ *
+ * you can set x/y as negative values, but the bubble will be outside the screen.
+ *
+ * @param x 0 ... screenWidth (px).
+ * @param y 0 ... screenHeight (px).
+ * */
+ fun startLocationPx(x: Int, y: Int): Builder {
+ startPoint.x = x
+ startPoint.y = y
return this
}
/**
* - 0.0f: invisible
* - 0.0f < x < 1.0f: view with opacity
- * - 1.0f: completely visible
+ * - 1.0f: fully visible
* */
fun opacity(opacity: Float): Builder {
this.opacity = opacity
diff --git a/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingBubbleService.kt b/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingBubbleService.kt
index 45dace1..eb52dac 100644
--- a/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingBubbleService.kt
+++ b/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingBubbleService.kt
@@ -8,19 +8,12 @@ import android.content.Intent
import android.graphics.Color
import android.os.Build
import android.os.IBinder
-import android.util.Log
import androidx.annotation.ChecksSdkIntAtLeast
import androidx.annotation.Discouraged
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationCompat.PRIORITY_MIN
import androidx.core.app.NotificationManagerCompat
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.GlobalScope
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.launch
abstract class FloatingBubbleService : Service() {
@@ -61,14 +54,14 @@ abstract class FloatingBubbleService : Service() {
when (currentRoute) {
Route.Empty -> {
- initViewsAndNotification()
+ startWithNotification()
}
Route.Bubble -> {
- initViewsAndNotification()
+ startWithNotification()
showBubbles()
}
Route.ExpandableView -> {
- initViewsAndNotification()
+ startWithNotification()
showExpandableView()
}
}
@@ -84,29 +77,18 @@ abstract class FloatingBubbleService : Service() {
* init view instances and notification
* */
@Throws(PermissionDeniedException::class)
- private fun initViewsAndNotification() {
+ private fun startWithNotification() {
if (!isDrawOverlaysPermissionGranted()) {
throw PermissionDeniedException()
}
- initViewInstances()
-
if (isHigherThanAndroid8()) {
showForegroundNotification()
}
}
- private fun initViewInstances() {
- floatingBubble = setupBubble(customFloatingBubbleAction)
- .addServiceInteractor(customFloatingBubbleServiceInteractor)
- .build()
-
- expandableView = setupExpandableView(customExpandableViewListener)
- ?.build()
- }
-
// region Public Methods -----------------------------------------------------------------------
/**
@@ -115,6 +97,11 @@ abstract class FloatingBubbleService : Service() {
fun currentRoute() = currentRoute
fun showBubbles() {
+ if (floatingBubble == null) {
+ floatingBubble = setupBubble(customFloatingBubbleAction)
+ .addServiceInteractor(customFloatingBubbleServiceInteractor)
+ .build()
+ }
floatingBubble!!.showIcon()
currentRoute = Route.Bubble
}
@@ -133,13 +120,19 @@ abstract class FloatingBubbleService : Service() {
@Throws(NotImplementedError::class)
fun showExpandableView(): Boolean {
if (expandableView == null) {
- throw NotImplementedError("you DID NOT override expandable view")
+
+ expandableView = setupExpandableView(customExpandableViewListener)
+ ?.build()
+
+ if (expandableView == null) {
+ throw NotImplementedError("you DID NOT override expandable view")
+ }
}
try {
expandableView!!.show()
currentRoute = Route.ExpandableView
} catch (e: Exception) {
- Log.e("<>", "showExpandableView: ", e)
+// Log.e("<>", "showExpandableView: ", e)
return false
}
@@ -151,16 +144,10 @@ abstract class FloatingBubbleService : Service() {
}
/**
- * remove all views or init notification if first-time call
+ * remove all views
* */
fun removeAllViews() {
- if (isNotificationInitialized.not()) {
- initViewsAndNotification()
- isNotificationInitialized = true
- return
- }
-
removeExpandableView()
removeBubbles()
diff --git a/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingBubbleView.kt b/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingBubbleView.kt
index b43f27c..66de034 100644
--- a/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingBubbleView.kt
+++ b/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingBubbleView.kt
@@ -3,12 +3,8 @@ package com.torrydo.floatingbubbleview
import android.annotation.SuppressLint
import android.graphics.Point
import android.graphics.PointF
-import android.util.Log
-import android.view.GestureDetector
+import android.view.*
import android.view.GestureDetector.SimpleOnGestureListener
-import android.view.LayoutInflater
-import android.view.MotionEvent
-import android.view.WindowManager
import com.torrydo.floatingbubbleview.databinding.BubbleBinding
internal class FloatingBubbleView(
@@ -41,7 +37,7 @@ internal class FloatingBubbleView(
}
halfIconWidthPx = width / 2
- halfIconHeightPx = height /2
+ halfIconHeightPx = height / 2
setupLayoutParams()
setupBubbleProperties()
@@ -181,7 +177,7 @@ internal class FloatingBubbleView(
builder.listener?.onDown(motionEvent.rawX, motionEvent.rawY)
}
- fun onActionMove(motionEvent: MotionEvent){
+ fun onActionMove(motionEvent: MotionEvent) {
builder.listener?.onMove(motionEvent.rawX, motionEvent.rawY)
}
@@ -191,7 +187,19 @@ internal class FloatingBubbleView(
// listen actions --------------------------------------------------------------------------
- val gestureDetector = GestureDetector(builder.context, SingleTapConfirm())
+ val gestureDetector = GestureDetector(builder.context, object : SimpleOnGestureListener() {
+
+// override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
+// builder.listener?.onClick()
+// return super.onSingleTapConfirmed(e)
+// }
+
+ override fun onSingleTapUp(e: MotionEvent): Boolean {
+ builder.listener?.onClick()
+ return super.onSingleTapUp(e)
+ }
+
+ })
binding.bubbleView.apply {
@@ -199,11 +207,7 @@ internal class FloatingBubbleView(
setOnTouchListener { _, motionEvent ->
- // detect onTouch event first. If event is consumed, return@setOnTouch...
- if (gestureDetector.onTouchEvent(motionEvent)) {
- builder.listener?.onClick()
- return@setOnTouchListener true
- }
+ gestureDetector.onTouchEvent(motionEvent)
when (motionEvent.action) {
MotionEvent.ACTION_DOWN -> onActionDown(motionEvent)
@@ -213,12 +217,7 @@ internal class FloatingBubbleView(
return@setOnTouchListener true
}
- }
- }
- private class SingleTapConfirm : SimpleOnGestureListener() {
- override fun onSingleTapUp(event: MotionEvent): Boolean {
- return true
}
}
diff --git a/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingCloseBubbleView.kt b/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingCloseBubbleView.kt
index a07f9fa..204492e 100644
--- a/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingCloseBubbleView.kt
+++ b/FloatingBubbleView/src/main/java/com/torrydo/floatingbubbleview/FloatingCloseBubbleView.kt
@@ -56,7 +56,7 @@ internal class FloatingCloseBubbleView(
centerCloseBubbleX = baseX + halfWidthPx
centerCloseBubbleY = baseY + halfHeightPx
- closablePerimeterPx = builder.closablePerimeterDp.toPx
+ closablePerimeterPx = builder.closablePerimeterDp.toPx()
setupLayoutParams()
setupCloseBubbleProperties()
@@ -121,7 +121,7 @@ internal class FloatingCloseBubbleView(
return distanceRatio
}
- fun distanceRatioFromLocationToClosableArea(x: Float, y: Float): Float{
+ fun distanceRatioFromLocationToClosableArea(x: Float, y: Float): Float {
val distanceToLocation = MathHelper.distance(
x1 = centerCloseBubbleX.toDouble(),
y1 = centerCloseBubbleY.toDouble(),
@@ -136,6 +136,7 @@ internal class FloatingCloseBubbleView(
return distanceRatio
}
+
fun animateCloseIconByBubble(x: Int, y: Int) {
val distanceRatio = distanceRatioFromBubbleToClosableArea(x, y)
diff --git a/README.md b/README.md
index 25e06ce..96efa1f 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# πFloating Bubble View
-An Android library that adds floating bubbles to your home screen π¨, supporting both XML and π Jetpack Compose
+An Android library that adds floating bubbles to your home screen π¨, supports both XML and π Jetpack Compose
@@ -158,7 +158,7 @@ Declare the dependencies in the module-level `build.gradle` file π Make sure "display over other apps" permission is granted, otherwise the app will crash β βπ₯
Java version
@@ -209,8 +209,9 @@ public class MyService extends FloatingBubbleService {
// set style for bubble, fade animation by default
.bubbleStyle(null)
- // set start location of bubble, (x=0, y=0) is the top-left
- .startLocation(0, 0)
+ // set start location for the bubble, (x=0, y=0) is the top-left
+ .startLocation(100, 100) // in dp
+ .startLocationPx(100, 100) // in px
// enable auto animate bubble to the left/right side when release, true by default
.enableAnimateToEdge(true)
@@ -224,8 +225,8 @@ public class MyService extends FloatingBubbleService {
// show close-bubble, true by default
.enableCloseBubble(true)
- // the more value (dp), the larger closeable-area
- .closablePerimeter(100)
+ // the more value (dp), the larger closable-area
+ .distanceToClose(100)
// choose behavior of the bubbles
// DYNAMIC_CLOSE_BUBBLE: close-bubble moving based on the bubble's location
@@ -307,8 +308,9 @@ class MyService : FloatingBubbleService() {
// set style for bubble, fade animation by default
.bubbleStyle(null)
- // set start location of bubble, (x=0, y=0) is the top-left
- .startLocation(0, 0)
+ // set start location for the bubble, (x=0, y=0) is the top-left
+ .startLocation(100, 100) // in dp
+ .startLocationPx(100, 100) // in px
// enable auto animate bubble to the left/right side when release, true by default
.enableAnimateToEdge(true)
@@ -323,7 +325,7 @@ class MyService : FloatingBubbleService() {
.enableCloseBubble(true)
// the more value (dp), the larger closeable-area
- .closablePerimeter(100)
+ .distanceToClose(100)
// choose behavior of the bubbles
// DYNAMIC_CLOSE_BUBBLE: close-bubble moving based on the bubble's location
@@ -353,7 +355,7 @@ class MyService : FloatingBubbleService() {
val layout = inflater.inflate(R.layout.layout_view_test, null)
layout.findViewById(R.id.card_view).setOnClickListener { v: View? ->
- Toast.makeText(this, "hello from card view from kotlin", Toast.LENGTH_SHORT).show();
+ Toast.makeText(this, "hello from kotlin", Toast.LENGTH_SHORT).show();
action.popToBubble()
}
diff --git a/app/src/main/java/com/torrydo/testfloatingbubble/MainActivityKt.kt b/app/src/main/java/com/torrydo/testfloatingbubble/MainActivityKt.kt
index 5e1e9d4..656ea71 100644
--- a/app/src/main/java/com/torrydo/testfloatingbubble/MainActivityKt.kt
+++ b/app/src/main/java/com/torrydo/testfloatingbubble/MainActivityKt.kt
@@ -27,6 +27,7 @@ class MainActivityKt : AppCompatActivity() {
stopMyService()
} else {
val intent = Intent(this, MyServiceKt::class.java)
+ intent.putExtra("size", 60)
ContextCompat.startForegroundService(this, intent)
isVisible = false
}
diff --git a/app/src/main/java/com/torrydo/testfloatingbubble/MyServiceKt.kt b/app/src/main/java/com/torrydo/testfloatingbubble/MyServiceKt.kt
index 4193f6f..4b2aa34 100644
--- a/app/src/main/java/com/torrydo/testfloatingbubble/MyServiceKt.kt
+++ b/app/src/main/java/com/torrydo/testfloatingbubble/MyServiceKt.kt
@@ -3,6 +3,7 @@ package com.torrydo.testfloatingbubble
import android.app.Notification
import android.app.PendingIntent
import android.content.Intent
+import android.util.Log
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
@@ -29,27 +30,31 @@ class MyServiceKt : FloatingBubbleService() {
}
-
}
override fun initialRoute(): Route {
- return Route.Bubble
+ return Route.Empty
}
+ private var size = 0
+
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- val route = intent?.getStringExtra("route") ?: return START_STICKY
+ val route = intent?.getStringExtra("route")
+
+ val _size = intent?.getIntExtra("size", 0)
+
+ size = _size ?: 0
- when(route){
+ showBubbles()
+
+ when (route) {
Route.Bubble.name -> {
showBubbles()
}
Route.ExpandableView.name -> {
showExpandableView()
}
- Route.Empty.name -> {
- removeAllViews()
- }
}
return START_STICKY
}
@@ -113,19 +118,20 @@ class MyServiceKt : FloatingBubbleService() {
return FloatingBubble.Builder(this)
// set bubble icon attributes, currently only drawable and bitmap are supported
- .bubble(R.drawable.ic_rounded_blue_diamond, 60, 60)
+ .bubble(R.drawable.ic_rounded_blue_diamond, size, size)
// set style for bubble, fade animation by default
.bubbleStyle(null)
- // set start location of bubble, (x=0, y=0) is the top-left
- .startLocation(0, 0)
+ // set start location for the bubble, (x=0, y=0) is the top-left
+ .startLocation(100, 100) // in dp
+// .startLocationPx(0, 0) // in px
- // enable auto animate bubble to the left/right side when release, true by default
+ // animate the bubble to the left/right side of the screen when finger is released, true by default
.enableAnimateToEdge(true)
// set close-bubble icon attributes, currently only drawable and bitmap are supported
- .closeBubble(R.drawable.ic_close_bubble, 60, 60)
+ .closeBubble(R.drawable.ic_close_bubble, size, size)
// set style for close-bubble, null by default
.closeBubbleStyle(null)
@@ -134,7 +140,7 @@ class MyServiceKt : FloatingBubbleService() {
.enableCloseBubble(true)
// the more value (dp), the larger closeable-area
- .closablePerimeter(100)
+ .distanceToClose(100)
// choose behavior of the bubbles
// DYNAMIC_CLOSE_BUBBLE: close-bubble moving based on the bubble's location
@@ -156,8 +162,13 @@ class MyServiceKt : FloatingBubbleService() {
) {
} // The location of the finger on the screen which triggers the movement of the bubble.
- override fun onUp(x: Float, y: Float) {} // ..., when finger release from bubble
- override fun onDown(x: Float, y: Float) {} // ..., when finger tap the bubble
+ override fun onUp(x: Float, y: Float) {
+ Log.d("<>", "onup: ${x} - ${y}");
+ } // ..., when finger release from bubble
+
+ override fun onDown(x: Float, y: Float) {
+ Log.d("<>", "ondown ${x}-${y}: ");
+ } // ..., when finger tap the bubble
})
// set bubble's opacity
.opacity(1f)
diff --git a/app/src/main/java/com/torrydo/testfloatingbubble/java_sample/MyService.java b/app/src/main/java/com/torrydo/testfloatingbubble/java_sample/MyService.java
index dcee1b0..47d8ffe 100644
--- a/app/src/main/java/com/torrydo/testfloatingbubble/java_sample/MyService.java
+++ b/app/src/main/java/com/torrydo/testfloatingbubble/java_sample/MyService.java
@@ -10,7 +10,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
-import androidx.core.content.ContextCompat;
import com.torrydo.floatingbubbleview.BubbleBehavior;
import com.torrydo.floatingbubbleview.ExpandableView;
@@ -117,7 +116,7 @@ public FloatingBubble.Builder setupBubble(@NonNull FloatingBubble.Action action)
.enableCloseBubble(true)
// the more value (dp), the larger closeable-area
- .closablePerimeter(100)
+ .distanceToClose(100)
// choose behavior of the bubbles
// DYNAMIC_CLOSE_BUBBLE: close-bubble moving based on the bubble's location
diff --git a/gradle.properties b/gradle.properties
index 4d9641d..675fbfc 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -27,8 +27,8 @@ RELEASE_SIGNING_ENABLED=true
GROUP=io.github.torrydo
POM_ARTIFACT_ID=floating-bubble-view
-VERSION_NAME=0.5.1
-#prev: 0.5.0
+VERSION_NAME=0.5.2
+#prev: 0.5.1
POM_NAME=FloatingBubbleView
POM_PACKAGING=aar