#5 Floating Windows on Android: Moving Window
Tags: android, kotlin, tutorial, learning
Published: 2020-10-14 12:25:51

Have you ever wondered how to make those floating windows used by Facebook Heads and other apps? Have you ever wanted to use the same technology in your app? It’s easy, and I will guide you through the whole process.

I'm the author of [Floating Apps](https://floatingapps.net); the first app of its kind on Google Play and the most popular one with over 8 million downloads. After 6 years of the development of the app, I know a bit about it. It’s sometimes tricky, and I spent months reading documentation and Android source code and experimenting. I received feedback from tens of thousands of users and see various issues on different phones with different Android versions.

Here's what I learned along the way. 

Before reading this article, it's recommended to go through [Floating Windows on Android 4: Floating Window](https://localazy.com/blog/floating-windows-on-android-4-floating-window).

**In this article, I will teach you how to make the window movable by dragging its header.**

## Updating Layout

In the previous article, we introduced how to add views to `WindowManager` along with their `LayoutParams`. However, from the moment the window is added, changes made to `LayoutParams` are not reflected. 

To apply changes, it's necessary to call method `updateViewLayout` of `WindowManager`. Therefore, we need to implement two additional methods for our `Window` class for changing the window position. 

```kotlin
private fun setPosition(x: Int, y: Int) {  
  windowParams.x = x  
  windowParams.y = y  
  update()  
}  

private fun update() {  
  try {  
    windowManager.updateViewLayout(rootView, windowParams)  
  } catch (e: Exception) {  
    // Ignore exception for now, but in production, you should have some  
    // warning for the user here.  
  }  
}
```

Of course, the very same principle can be used to change the window's size, opacity, etc.

## Custom OnTouchListener


For moving the window, let's implement a custom `OnTouchListener` that allows us to track the initial point's movement. Also, let's keep the basic functionality - clicks & long-clicks - to work in the expected system-like way. 

Our implementation doesn't support multitouch, but it's good enough to demonstrate how to move the window. 

The source code of our new `DraggableTouchListener` is here:

```kotlin
class DraggableTouchListener(
    context: Context,
    private val view: View,
    private val initialPosition: () -> Point,
    private val positionListener: (x: Int, y: Int) -> Unit
) : View.OnTouchListener {

  private val touchSlop = ViewConfiguration.get(context).scaledTouchSlop
  private val longClickInterval = ViewConfiguration.getLongPressTimeout()
  private var pointerStartX = 0
  private var pointerStartY = 0
  private var initialX = 0
  private var initialY = 0
  private var moving = false
  private var longClickPerformed = false
  private var timer: Timer? = null

  init {
    view.setOnTouchListener(this)
  }

  private fun scheduleLongClickTimer() {
    if (timer == null) {
      timer = Timer()
      timer?.schedule(timerTask {
          if (!moving && !longClickPerformed) {
              view.post {
                  view.performLongClick()
              }
              longClickPerformed = true
          }
          cancelLongClickTimer()
      }, longClickInterval.toLong())
    }
  }

  private fun cancelLongClickTimer() {
    timer?.cancel()
    timer = null
  }

  override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {

    when (motionEvent.action) {

        MotionEvent.ACTION_DOWN -> {
            pointerStartX = motionEvent.rawX.toInt()
            pointerStartY = motionEvent.rawY.toInt()
            with(initialPosition()) {
                initialX = x
                initialY = y
            }
            moving = false
            longClickPerformed = false
            scheduleLongClickTimer()
        }

        MotionEvent.ACTION_MOVE -> {
            if (!longClickPerformed) {
                val deltaX = motionEvent.rawX - pointerStartX
                val deltaY = motionEvent.rawY - pointerStartY
                if (moving || hypot(deltaX, deltaY) > touchSlop) {
                    cancelLongClickTimer()
                    positionListener(initialX + deltaX.toInt(), initialY + deltaY.toInt())
                    moving = true
                }
            }
        }

        MotionEvent.ACTION_UP -> {
            cancelLongClickTimer()
            if (!moving && !longClickPerformed) {
                view.performClick()
            }
        }

    }

    return true
  }
  
}
```

We can add a bit of Kotlin magic - extension functions - to make it even easier to use:

```kotlin
fun View.registerDraggableTouchListener(  
  initialPosition: () -> Point,  
  positionListener: (x: Int, y: Int) -> Unit  
) {  
  DraggableTouchListener(context, this, initialPosition, positionListener)  
}
```

Theoretically, you can move anything with code above - the view serves here as a trigger only. 

## Let's Get The Window Movin'

Everything we need to do is to attach our newly created `DraggableTouchListener` to the view we want to be used as a handle for moving the window. 

For desktop operating systems, the window's title bar typically serves this purpose, so let's follow the same trend:

```kotlin
rootView.findViewById<View>(R.id.window_header).registerDraggableTouchListener(  
  initialPosition = { Point(windowParams.x, windowParams.y) },  
  positionListener = { x, y -> setPosition(x, y) }  
)
```

**And that's it!**

## Boundaries


It would be necessary for the productional use to implement some boundaries, so the window can’t be moved out of the screen too much.

In Floating Apps, I allow the user to move 50% of the window outside the screen area.

## Results

Tap the window's title bar and move it anywhere you want! 

{% youtube fyTKObr6ZUA %}

## Source Code
The whole source code for this article is [available on Github](https://github.com/vaclavhodek/quicknote_5).

## Stay Tuned

Eager to learn more about Android development? Follow me (<a href="https://twitter.com/vaclavhodek">@vaclavhodek</a>) and Localazy (<a href="https://twitter.com/localazy">@localazy</a>) on Twitter, or like <a href="https://www.facebook.com/localazy">Localazy on Facebook</a>.

## The Series

This article is part of the **Floating Windows on Android** series. 

- [Floating Windows on Android 1: Jetpack Compose & Room](https://localazy.com/blog/floating-windows-on-android-1-jetpack-compose-and-room)
- [Floating Windows on Android 2: Foreground Service](https://localazy.com/blog/floating-windows-on-android-2-foreground-service)
- [Floating Windows on Android 3: Permissions](https://localazy.com/blog/floating-windows-on-android-3-permissions)
- [Floating Windows on Android 4: Floating Window](https://localazy.com/blog/floating-windows-on-android-4-floating-window)
- [Floating Windows on Android 5: Moving Window](https://localazy.com/blog/floating-windows-on-android-5-moving-window)
- [Floating Windows on Android 6: Keyboard Input](https://localazy.com/blog/floating-windows-on-android-6-keyboard-input)
- [Floating Windows on Android 7: Boot Receiver](https://localazy.com/blog/floating-windows-on-android-7-boot-receiver)
- [Floating Windows on Android 8: The Final App](https://localazy.com/blog/floating-windows-on-android-8-the-final-app)
- [Floating Windows on Android 9: Shortcomings](https://localazy.com/blog/floating-windows-on-android-9-shortcomings)
- [Floating Windows on Android 10: Tips & Tricks](https://localazy.com/blog/floating-windows-on-android-10-tips-and-tricks)