Skip to content

Instantly share code, notes, and snippets.

@kakajika
Last active March 30, 2024 14:46
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kakajika/973667ccc945a1ad10e6eba0cef0f793 to your computer and use it in GitHub Desktop.
Save kakajika/973667ccc945a1ad10e6eba0cef0f793 to your computer and use it in GitHub Desktop.
Android Service implementation with fullscreen overlay window (over status bar & navigation bar)
class FullscreenOverlayService extends Service {
private View overlay;
private WindowManager windowManager;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
overlay = View.inflate(getApplicationContext(), R.layout.overlay_service, null);
overlay.findViewById(R.id.button_stop).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopSelf();
}
});
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |
WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT
);
layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
windowManager.addView(overlay, layoutParams);
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
windowManager.removeView(overlay);
}
}
class FullscreenOverlayLayout extends FrameLayout {
// コンストラクタ...
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
WindowManager windowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Point screenSize = new Point();
windowManager.getDefaultDisplay().getRealSize(screenSize);
super.onMeasure(
MeasureSpec.makeMeasureSpec(screenSize.x, MeasureSpec.getMode(widthMeasureSpec)),
MeasureSpec.makeMeasureSpec(screenSize.y, MeasureSpec.getMode(heightMeasureSpec))
);
}
}
class OverlayDrawingView extends View {
// コンストラクタ...
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// カスタム描画処理...
}
}
class FullscreenOverlayService : Service() {
private val overlay by lazy {
View.inflate(applicationContext, R.layout.overlay_service, null).also {
it.button_stop.setOnClickListener {
stopSelf()
}
}
}
private val windowManager by lazy {
applicationContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager
}
override fun onBind(intent: Intent?): IBinder? {
return null
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
val layoutParams = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
WindowManager.LayoutParams.FLAG_FULLSCREEN or
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR or
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT
).also {
it.gravity = Gravity.LEFT or Gravity.TOP
}
windowManager.addView(overlay, layoutParams)
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
windowManager.removeView(overlay)
}
}
class FullscreenOverlayLayout @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
val screenSize = Point().also { windowManager.defaultDisplay.getRealSize(it) }
super.onMeasure(
MeasureSpec.makeMeasureSpec(screenSize.x, MeasureSpec.getMode(widthMeasureSpec)),
MeasureSpec.makeMeasureSpec(screenSize.y, MeasureSpec.getMode(heightMeasureSpec))
)
}
}
class OverlayDrawingView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
private val paint by lazy {
Paint().apply {
color = Color.LTGRAY
style = Paint.Style.STROKE
strokeWidth = 8f
}
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
if (canvas != null && canvas.width > 0) {
val W = canvas.width
val H = canvas.height
val interval = W / STEP
// 斜めパターンの描画
generateSequence(0f) { it + interval }
.take(STEP + H / interval + 1)
.forEach { canvas.drawLine(it, 0f, 0f, it, paint) }
canvas.drawRect(0f, 0f, W.toFloat(), H.toFloat(), paint)
}
}
companion object {
private const val STEP = 9
}
}
<?xml version="1.0" encoding="utf-8"?>
<com.labo.kaji.playground.FullscreenOverlayLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.labo.kaji.playground.OverlayDrawingView
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_gravity="center"
>
<TextView
android:id="@+id/text_hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello Overlay!"
android:textSize="16sp"
android:textColor="#FFF"
/>
<Button
android:id="@+id/button_stop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="Stop"
/>
</LinearLayout>
</com.labo.kaji.playground.FullscreenOverlayLayout>
@zqunyan
Copy link

zqunyan commented Feb 5, 2021

the window is on navigationbar area can not click?

@SanioLukeIDE
Copy link

Thank you. You code thanked me a lot. I have been searching for this code for last 4 days and i was at the edge of giving hope. Thank you so much

@aikorola
Copy link

aikorola commented Jan 4, 2024

Thank you very, very, very much

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment