Last active
April 16, 2025 06:54
-
-
Save kakajika/973667ccc945a1ad10e6eba0cef0f793 to your computer and use it in GitHub Desktop.
Android Service implementation with fullscreen overlay window (over status bar & navigation bar)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
// カスタム描画処理... | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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> |
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
Thank you very, very, very much
bro it works out! but does not covers the top notification area only covers the bottom navigation area
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
the window is on navigationbar area can not click?