Skip to content
This repository was archived by the owner on Jan 5, 2021. It is now read-only.

Commit acded9e

Browse files
author
Luis Correa
committed
Floating Window Service, network stats
1 parent 1c573a2 commit acded9e

File tree

6 files changed

+277
-0
lines changed

6 files changed

+277
-0
lines changed

android/app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
android:name="io.flutter.app.FlutterApplication"
1515
android:label="TODO"
1616
android:icon="@mipmap/launcher_icon">
17+
18+
<service android:name=".FloatingWindow" />
19+
1720
<activity
1821
android:name=".MainActivity"
1922
android:launchMode="singleTop"
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
package com.cubanopensource.todo
2+
3+
import android.app.Activity
4+
import android.app.Service
5+
import android.content.Context
6+
import android.content.Intent
7+
import android.content.SharedPreferences
8+
import android.graphics.Color
9+
import android.graphics.PixelFormat
10+
import android.net.TrafficStats
11+
import android.os.Build
12+
import android.os.Handler
13+
import android.os.IBinder
14+
import android.provider.Settings
15+
import android.util.DisplayMetrics
16+
import android.view.*
17+
import android.widget.RelativeLayout
18+
import android.widget.TextView
19+
20+
21+
class FloatingWindow : Service() {
22+
23+
private var mLastRxBytes: Long = 0
24+
private var mLastTxBytes: Long = 0
25+
private var mLastTime: Long = 0
26+
27+
private val mHandler = Handler()
28+
29+
private lateinit var tv: TextView
30+
31+
lateinit var preferences: SharedPreferences
32+
33+
private val mHandlerRunnable = object : Runnable {
34+
override fun run() {
35+
val currentRxBytes = TrafficStats.getTotalRxBytes()
36+
val currentTxBytes = TrafficStats.getTotalTxBytes()
37+
val usedRxBytes = currentRxBytes - mLastRxBytes
38+
val usedTxBytes = currentTxBytes - mLastTxBytes
39+
val currentTime = System.currentTimeMillis()
40+
val usedTime = currentTime - mLastTime
41+
42+
mLastRxBytes = currentRxBytes
43+
mLastTxBytes = currentTxBytes
44+
mLastTime = currentTime
45+
46+
tv.text = calcSpeed(usedTime, usedRxBytes, usedTxBytes)
47+
48+
mHandler.postDelayed(this, 1000)
49+
}
50+
}
51+
52+
fun calcSpeed(timeTaken: Long, downBytes: Long, upBytes: Long): String {
53+
var downSpeed: Long = 0
54+
var upSpeed: Long = 0
55+
56+
if (timeTaken > 0) {
57+
downSpeed = downBytes * 1000 / timeTaken
58+
upSpeed = upBytes * 1000 / timeTaken
59+
}
60+
61+
val mDownSpeed = downSpeed
62+
val mUpSpeed = upSpeed
63+
64+
val down = setSpeed(mDownSpeed)
65+
val up = setSpeed(mUpSpeed)
66+
67+
return "$up$down "
68+
}
69+
70+
private fun setSpeed(speed: Long): String {
71+
if (speed < 1000000) {
72+
return "%.1f KB".format((speed / 1000.0))
73+
} else if (speed >= 1000000) {
74+
if (speed < 10000000) {
75+
return "%.1f MB".format((speed / 1000000.0))
76+
} else if (speed < 100000000) {
77+
return "%.1f MB".format((speed / 1000000.0))
78+
} else {
79+
return "+99 MB"
80+
}
81+
} else {
82+
return "-"
83+
}
84+
}
85+
86+
override fun onCreate() {
87+
super.onCreate()
88+
89+
mLastRxBytes = TrafficStats.getTotalRxBytes()
90+
mLastTxBytes = TrafficStats.getTotalTxBytes()
91+
mLastTime = System.currentTimeMillis()
92+
93+
showFloatWidget()
94+
}
95+
96+
private fun showFloatWidget() {
97+
if (getDrawPermissionState()) {
98+
preferences = applicationContext.getSharedPreferences("${packageName}_preferences", Activity.MODE_PRIVATE)
99+
100+
val displayMetrics = DisplayMetrics()
101+
(getSystemService(Context.WINDOW_SERVICE) as WindowManager).defaultDisplay.getMetrics(displayMetrics)
102+
val height = displayMetrics.heightPixels
103+
val width = displayMetrics.widthPixels
104+
105+
// Close traffic stats widget
106+
val closeView = LayoutInflater.from(this).inflate(R.layout.close_float_widget, null)
107+
108+
val closeWM = getSystemService(Context.WINDOW_SERVICE) as WindowManager
109+
110+
val parameters_close: WindowManager.LayoutParams
111+
112+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
113+
parameters_close = WindowManager.LayoutParams(
114+
width,
115+
WindowManager.LayoutParams.WRAP_CONTENT,
116+
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
117+
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
118+
PixelFormat.TRANSLUCENT
119+
)
120+
else
121+
parameters_close = WindowManager.LayoutParams(
122+
width,
123+
WindowManager.LayoutParams.WRAP_CONTENT,
124+
WindowManager.LayoutParams.TYPE_PHONE,
125+
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
126+
PixelFormat.TRANSLUCENT
127+
)
128+
129+
parameters_close.gravity = Gravity.BOTTOM
130+
131+
// Traffic Stats widget
132+
val widgetView = LayoutInflater.from(this).inflate(R.layout.float_window, null) as RelativeLayout
133+
134+
/*
135+
<TextView
136+
android:padding="2dp"
137+
android:id="@+id/traffic_text"
138+
android:layout_width="wrap_content"
139+
android:layout_height="wrap_content"
140+
android:layout_centerInParent="true"
141+
android:text="up 0 | down 0"
142+
android:textColor="@android:color/white"
143+
android:textStyle="bold" />
144+
*/
145+
tv = TextView(this)
146+
tv.setPadding(2, 4, 2, 4)
147+
tv.setTextColor(Color.WHITE)
148+
tv.textSize = 11f
149+
tv.text = "up 0 | down 0"
150+
151+
widgetView.addView(tv)
152+
153+
val wm = getSystemService(Context.WINDOW_SERVICE) as WindowManager
154+
155+
val parameters: WindowManager.LayoutParams
156+
157+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
158+
parameters = WindowManager.LayoutParams(
159+
WindowManager.LayoutParams.WRAP_CONTENT,
160+
WindowManager.LayoutParams.WRAP_CONTENT,
161+
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
162+
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
163+
PixelFormat.TRANSLUCENT
164+
)
165+
else
166+
parameters = WindowManager.LayoutParams(
167+
WindowManager.LayoutParams.WRAP_CONTENT,
168+
WindowManager.LayoutParams.WRAP_CONTENT,
169+
WindowManager.LayoutParams.TYPE_PHONE,
170+
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
171+
PixelFormat.TRANSLUCENT
172+
)
173+
174+
175+
val fx = preferences.getInt("float_widget_x", 0)
176+
val fy = preferences.getInt("float_widget_y", 0)
177+
178+
println(fx)
179+
println(fy)
180+
181+
parameters.x = fx
182+
parameters.y = fy
183+
parameters.gravity = Gravity.CENTER
184+
wm.addView(widgetView, parameters)
185+
186+
// Traffic stats on touch handler
187+
widgetView.setOnTouchListener(object : View.OnTouchListener {
188+
private var updatedParameters: WindowManager.LayoutParams = parameters
189+
var x: Int = 0
190+
var y: Int = 0
191+
192+
var touchedX: Float = 0.0f
193+
var touchedY: Float = 0.0f
194+
195+
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
196+
when (event?.action) {
197+
MotionEvent.ACTION_DOWN -> {
198+
x = updatedParameters.x
199+
y = updatedParameters.y
200+
201+
touchedX = event.rawX
202+
touchedY = event.rawY
203+
204+
closeWM.addView(closeView, parameters_close)
205+
}
206+
MotionEvent.ACTION_MOVE -> {
207+
updatedParameters.x = (x + (event.rawX - touchedX)).toInt()
208+
updatedParameters.y = (y + (event.rawY - touchedY)).toInt()
209+
210+
wm.updateViewLayout(widgetView, updatedParameters)
211+
}
212+
213+
MotionEvent.ACTION_UP -> {
214+
if (event.rawY.toInt() >= height - 100) {
215+
wm.removeView(widgetView)
216+
} else {
217+
with(preferences.edit()) {
218+
putInt("float_widget_x", updatedParameters.x)
219+
putInt("float_widget_y", updatedParameters.y)
220+
221+
apply()
222+
}
223+
}
224+
225+
closeWM.removeView(closeView)
226+
}
227+
}
228+
229+
return false
230+
}
231+
})
232+
233+
mHandler.post(mHandlerRunnable)
234+
}
235+
}
236+
237+
private fun getDrawPermissionState(): Boolean {
238+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
239+
return (Settings.canDrawOverlays(this))
240+
241+
return true
242+
}
243+
244+
override fun onBind(intent: Intent?): IBinder? {
245+
return null
246+
}
247+
}

android/app/src/main/kotlin/com/cubanopensource/todo/MainActivity.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ class MainActivity: FlutterActivity() {
2323
else -> result.notImplemented()
2424
}
2525
}
26+
27+
if(getDrawPermissionState()) {
28+
startService(Intent(this, FloatingWindow::class.java))
29+
}
2630
}
2731

2832
private fun getDrawPermissionState(): Boolean {
2.24 KB
Loading
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:layout_width="match_parent"
4+
android:layout_height="match_parent"
5+
android:background="#aaFF0000"
6+
android:gravity="bottom"
7+
android:orientation="vertical">
8+
9+
<ImageButton
10+
android:layout_width="match_parent"
11+
android:layout_height="wrap_content"
12+
android:background="@android:color/transparent"
13+
android:src="@drawable/close" />
14+
</LinearLayout>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:id="@+id/float_window_layout"
4+
android:layout_width="match_parent"
5+
android:layout_height="match_parent"
6+
android:background="#7a000000">
7+
8+
9+
</RelativeLayout>

0 commit comments

Comments
 (0)