Skip to content

Commit f4ef85f

Browse files
committed
Init git
0 parents  commit f4ef85f

58 files changed

Lines changed: 1595 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
*.iml
2+
.gradle
3+
/local.properties
4+
/.idea
5+
.DS_Store
6+
/build
7+
/captures
8+
.externalNativeBuild
9+
.cxx
10+
local.properties

FloatingOverlayView/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
plugins {
2+
id("com.android.library")
3+
id("org.jetbrains.kotlin.android")
4+
}
5+
6+
android {
7+
namespace = "com.buildtoapp.floatingoverlayview"
8+
compileSdk = 29
9+
10+
defaultConfig {
11+
minSdk = 19
12+
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
13+
consumerProguardFiles("consumer-rules.pro")
14+
}
15+
buildTypes {
16+
release {
17+
isMinifyEnabled = false
18+
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
19+
}
20+
}
21+
compileOptions {
22+
sourceCompatibility = JavaVersion.VERSION_1_8
23+
targetCompatibility = JavaVersion.VERSION_1_8
24+
}
25+
kotlinOptions {
26+
jvmTarget = "1.8"
27+
}
28+
}
29+
30+
dependencies {
31+
implementation("androidx.appcompat:appcompat:1.2.0")
32+
}

FloatingOverlayView/consumer-rules.pro

Whitespace-only changes.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.buildtoapp.floatingoverlayview
2+
3+
import androidx.test.platform.app.InstrumentationRegistry
4+
import androidx.test.ext.junit.runners.AndroidJUnit4
5+
6+
import org.junit.Test
7+
import org.junit.runner.RunWith
8+
9+
import org.junit.Assert.*
10+
11+
/**
12+
* Instrumented test, which will execute on an Android device.
13+
*
14+
* See [testing documentation](http://d.android.com/tools/testing).
15+
*/
16+
@RunWith(AndroidJUnit4::class)
17+
class ExampleInstrumentedTest {
18+
@Test
19+
fun useAppContext() {
20+
// Context of the app under test.
21+
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22+
assertEquals("com.buildtoapp.floatingoverlayview.test", appContext.packageName)
23+
}
24+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
3+
4+
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
5+
6+
<application>
7+
<service
8+
android:name=".service.FloatingOverlayService"
9+
android:exported="false" />
10+
</application>
11+
</manifest>
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.buildtoapp.floatingoverlayview
2+
3+
import android.content.Context
4+
import android.content.Intent
5+
import android.os.Build
6+
import android.os.Handler
7+
import android.os.Looper
8+
import android.provider.Settings
9+
import android.util.Log
10+
import androidx.annotation.LayoutRes
11+
import com.buildtoapp.floatingoverlayview.callback.OnCloseListener
12+
import com.buildtoapp.floatingoverlayview.callback.OnCreateListener
13+
import com.buildtoapp.floatingoverlayview.receiver.FloatingResultReceiver
14+
import com.buildtoapp.floatingoverlayview.service.FloatingOverlayService
15+
16+
class FloatingOverlayView(private val context: Context, @LayoutRes private val layoutRes: Int) {
17+
private var onCreateListener: OnCreateListener? = null
18+
private var onCloseListener: OnCloseListener? = null
19+
private var xOffset = 0
20+
private var yOffset = 0
21+
var isVisible = false
22+
private set
23+
24+
fun setOnCreateListener(onCreateListener: OnCreateListener): FloatingOverlayView {
25+
this.onCreateListener = onCreateListener
26+
return this
27+
}
28+
29+
fun setOnCloseListener(onCloseListener: OnCloseListener): FloatingOverlayView {
30+
this.onCloseListener = onCloseListener
31+
return this
32+
}
33+
34+
fun setXOffset(xOffset: Int): FloatingOverlayView {
35+
this.xOffset = xOffset
36+
return this
37+
}
38+
39+
fun setYOffset(yOffset: Int): FloatingOverlayView {
40+
this.yOffset = yOffset
41+
return this
42+
}
43+
44+
fun create(): FloatingOverlayView? {
45+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
46+
Log.e(TAG, "Draw over other apps is not supported below Android 6")
47+
return null
48+
}
49+
if (!Settings.canDrawOverlays(context)) {
50+
throw IllegalStateException(
51+
"""
52+
Cannot show overlay view without draw over other apps permission
53+
Use startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION)) to grant the permission
54+
"""
55+
)
56+
}
57+
isVisible = true
58+
val intent = getIntent(context)
59+
intent.putExtra(FloatingOverlayService.EXTRA_LAYOUT_RESOURCE, layoutRes)
60+
intent.putExtra(FloatingOverlayService.EXTRA_X_OFFSET, xOffset)
61+
intent.putExtra(FloatingOverlayService.EXTRA_Y_OFFSET, yOffset)
62+
stopService(context)
63+
if (onCreateListener != null || onCloseListener != null) {
64+
val handler = Handler(Looper.getMainLooper())
65+
val receiver = FloatingResultReceiver(this, onCreateListener, onCloseListener, handler)
66+
intent.putExtra(FloatingOverlayService.EXTRA_RECEIVER, receiver)
67+
}
68+
context.startService(intent)
69+
return this
70+
}
71+
72+
fun destroy() {
73+
isVisible = false
74+
stopService(context)
75+
}
76+
77+
companion object {
78+
private const val TAG = "FloatingOverlayView"
79+
private fun getIntent(context: Context) = Intent(context, FloatingOverlayService::class.java)
80+
81+
@JvmStatic
82+
fun stopService(context: Context) {
83+
val intent = getIntent(context)
84+
context.stopService(intent)
85+
}
86+
}
87+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.buildtoapp.floatingoverlayview.callback
2+
3+
import android.view.View
4+
import com.buildtoapp.floatingoverlayview.FloatingOverlayView
5+
6+
fun interface OnCreateListener {
7+
fun onCreate(layout: FloatingOverlayView, view: View)
8+
}
9+
10+
fun interface OnCloseListener {
11+
fun onClose()
12+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.buildtoapp.floatingoverlayview.component
2+
3+
import android.content.Context
4+
import android.os.Bundle
5+
import android.os.ResultReceiver
6+
import android.view.View
7+
import com.buildtoapp.floatingoverlayview.module.FloatingViewMovementModule
8+
import com.buildtoapp.floatingoverlayview.module.FloatingWindowModule
9+
10+
internal class FloatingComponent(
11+
private val layoutRes: Int,
12+
private val context: Context,
13+
private val xOffset: Int,
14+
private val yOffset: Int
15+
) {
16+
private var receiver: ResultReceiver? = null
17+
var floatingWindowModule: FloatingWindowModule? = null
18+
private set
19+
private var floatingViewMovementModule: FloatingViewMovementModule? = null
20+
21+
fun setUp() {
22+
floatingWindowModule = FloatingWindowModule(context, layoutRes)
23+
floatingWindowModule?.create()
24+
val floatingView = floatingWindowModule?.getView()
25+
val rootContainer = floatingView?.findViewById<View>(viewRootId)
26+
floatingViewMovementModule = FloatingViewMovementModule(
27+
floatingWindowModule?.getParams(),
28+
rootContainer,
29+
floatingWindowModule?.windowManager,
30+
floatingView,
31+
xOffset,
32+
yOffset
33+
)
34+
floatingViewMovementModule?.run()
35+
sendAction(ACTION_ON_CREATE, Bundle())
36+
}
37+
38+
fun setReceiver(receiver: ResultReceiver?) {
39+
this.receiver = receiver
40+
}
41+
42+
private val viewRootId: Int
43+
get() = context.resources.getIdentifier("root_container", "id", context.packageName)
44+
45+
private fun sendAction(action: Int, bundle: Bundle) {
46+
receiver?.send(action, bundle)
47+
}
48+
49+
fun destroy() {
50+
sendAction(ACTION_ON_CLOSE, Bundle())
51+
floatingWindowModule?.destroy()
52+
floatingViewMovementModule?.destroy()
53+
floatingWindowModule = null
54+
floatingViewMovementModule = null
55+
}
56+
57+
companion object {
58+
const val ACTION_ON_CREATE = 0x0002
59+
const val ACTION_ON_CLOSE = 0x00001
60+
}
61+
}

0 commit comments

Comments
 (0)