Last active
November 11, 2024 18:34
-
-
Save sjf/ae050683a8d790dcb3260b5ffc610b87 to your computer and use it in GitHub Desktop.
Android screen overlay example. Draws a button over other apps.
This file contains 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"?> | |
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:app="http://schemas.android.com/apk/res-auto" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
tools:context=".MainActivity"> | |
<TextView | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:text="Overlay example" | |
app:layout_constraintBottom_toBottomOf="parent" | |
app:layout_constraintLeft_toLeftOf="parent" | |
app:layout_constraintRight_toRightOf="parent" | |
app:layout_constraintTop_toTopOf="parent" /> | |
</android.support.design.widget.CoordinatorLayout> |
This file contains 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
package io.sjf.overlay; | |
import android.annotation.TargetApi; | |
import android.content.Intent; | |
import android.net.Uri; | |
import android.os.Build; | |
import android.os.Bundle; | |
import android.provider.Settings; | |
import android.support.v7.app.AppCompatActivity; | |
import android.support.v7.widget.Toolbar; | |
import android.util.Log; | |
import android.view.Menu; | |
import android.view.MenuItem; | |
public class MainActivity extends AppCompatActivity { | |
private static final String TAG = "Overlay"; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.activity_main); | |
if (checkDrawOverlayPermission()) { | |
startOverlayService(); | |
} | |
} | |
private static int REQUEST_CODE = 1; | |
private boolean checkDrawOverlayPermission() { | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { | |
/** check if we already have permission to draw over other apps */ | |
if (!Settings.canDrawOverlays(this)) { | |
Log.d(TAG, "canDrawOverlays NOK"); | |
/** if not construct intent to request permission */ | |
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, | |
Uri.parse("package:" + getPackageName())); | |
/** request permission via start activity for result */ | |
startActivityForResult(intent, REQUEST_CODE); | |
return false; | |
} else { | |
Log.d(TAG, "canDrawOverlays OK"); | |
} | |
} | |
return true; | |
} | |
@Override | |
@TargetApi(Build.VERSION_CODES.M) | |
protected void onActivityResult(int requestCode, int resultCode, Intent data) { | |
/** check if received result code | |
is equal our requested code for draw permission */ | |
if (requestCode == REQUEST_CODE) { | |
if (Settings.canDrawOverlays(this)) { | |
startOverlayService(); | |
} | |
} | |
} | |
private void startOverlayService() { | |
Intent intent = new Intent(this, OverlayService.class); | |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | |
startForegroundService(intent); | |
} else { | |
startService(intent); | |
} | |
} | |
} |
This file contains 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"?> | |
<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
package="io.sjf.overlay"> | |
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> | |
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> | |
<application | |
android:allowBackup="true" | |
android:icon="@mipmap/ic_launcher" | |
android:label="@string/app_name" | |
android:roundIcon="@mipmap/ic_launcher_round" | |
android:supportsRtl="true" | |
android:theme="@style/AppTheme"> | |
<activity | |
android:name=".MainActivity" | |
android:label="@string/app_name" | |
android:theme="@style/AppTheme.NoActionBar"> | |
<intent-filter> | |
<action android:name="android.intent.action.MAIN" /> | |
<category android:name="android.intent.category.LAUNCHER" /> | |
</intent-filter> | |
</activity> | |
<service | |
android:name=".OverlayService" | |
android:exported="false"/> | |
</application> | |
</manifest> |
This file contains 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
package io.sjf.overlay; | |
import android.app.Notification; | |
import android.app.NotificationChannel; | |
import android.app.NotificationManager; | |
import android.app.Service; | |
import android.content.Context; | |
import android.content.Intent; | |
import android.graphics.Color; | |
import android.graphics.PixelFormat; | |
import android.os.Build; | |
import android.os.IBinder; | |
import android.support.annotation.Nullable; | |
import android.support.v4.app.NotificationCompat; | |
import android.util.Log; | |
import android.view.Gravity; | |
import android.view.MotionEvent; | |
import android.view.View; | |
import android.view.View.OnClickListener; | |
import android.view.View.OnTouchListener; | |
import android.view.WindowManager; | |
import android.widget.Button; | |
public class OverlayService extends Service implements OnTouchListener, OnClickListener { | |
private static String TAG = "OverlayService"; | |
private WindowManager wm; | |
private Button button; | |
@Override | |
public int onStartCommand(Intent intent, int flags, int startId) { | |
super.onCreate(); | |
if (Build.VERSION.SDK_INT >= 26) { | |
String CHANNEL_ID = "channel1"; | |
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, | |
"Overlay notification", | |
NotificationManager.IMPORTANCE_LOW); | |
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)) | |
.createNotificationChannel(channel); | |
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) | |
.setContentTitle("adsf") | |
.setContentText("asdf1") | |
.setSmallIcon(R.drawable.ic_launcher_foreground) | |
.build(); | |
startForeground(1, notification); | |
} | |
wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE); | |
button = new Button(this); | |
button.setBackgroundResource(R.drawable.ic_button1); | |
button.setText("Button"); | |
button.setAlpha(1); | |
button.setBackgroundColor(Color.BLUE); | |
button.setOnClickListener(this); | |
int type = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O | |
? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY | |
: WindowManager.LayoutParams.TYPE_PHONE; | |
WindowManager.LayoutParams params = new WindowManager.LayoutParams( | |
WindowManager.LayoutParams.WRAP_CONTENT, | |
WindowManager.LayoutParams.WRAP_CONTENT, | |
type, | |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, | |
PixelFormat.TRANSLUCENT); | |
params.gravity = Gravity.START | Gravity.TOP; | |
params.x = 0; | |
params.y = 0; | |
wm.addView(button, params); | |
return START_NOT_STICKY; | |
} | |
@Override | |
public boolean onTouch(View v, MotionEvent event) { | |
Log.d(TAG, " ++++ On touch"); | |
return false; | |
} | |
@Override | |
public void onClick(View v) { | |
Log.d(TAG, " ++++ On click"); | |
} | |
@Override | |
public void onDestroy() { | |
super.onDestroy(); | |
if (button != null) { | |
wm.removeView(button); | |
button = null; | |
} | |
} | |
@Override | |
@Nullable | |
public IBinder onBind(Intent intent) { | |
return null; | |
} | |
} |
Can it move able?
@prokash447 you can control the positioning with the params.x/y passed to wm.addView here (Line 70)
when i open the setting app(system setting) the overlay does not work. why? have any solution?
Hello,
I see a blank activity that blocks touch events to home screen/ apps underneath. Are we missing any other configurations?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is awesome. Thank you!!!!