Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save vtabk2/5a83115c2b61afb3e5101b6f082a6ffe to your computer and use it in GitHub Desktop.
Save vtabk2/5a83115c2b61afb3e5101b6f082a6ffe 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment