安卓锁屏上层显示带IME支持的UI(Service初始化)求解决方案
I've tackled similar requirements before, and the key issues with your current approaches are mostly around window flags, focusability, and proper permission handling. Let's break down the correct approach to get your EditText (with IME support) showing over any lock screen (PIN/password or swipe):
Step 1: Required Permissions
First, you need the system overlay permission, which is a special permission that can't be requested via normal runtime permissions. Add this to your AndroidManifest.xml:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <!-- Optional, but helps with keeping the screen awake reliably --> <uses-permission android:name="android.permission.WAKE_LOCK" />
Before creating your window, check if you have the overlay permission. If not, redirect the user to the settings page to grant it:
if (!Settings.canDrawOverlays(this)) { Intent overlayIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); overlayIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(overlayIntent); return; // Exit until permission is granted }
Step 2: Correct WindowManager Configuration
Your first attempt used FLAG_NOT_FOCUSABLE, which blocks your EditText from gaining focus (and thus showing the IME). Here's the adjusted LayoutParams that works reliably over lock screens:
WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT, // Use TYPE_APPLICATION_OVERLAY for Android 8.0+, fallback to TYPE_SYSTEM_ALERT for older versions Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY : WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, // Critical flags for lock screen behavior and focus WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // Let touches outside your UI pass through to the lock screen PixelFormat.TRANSLUCENT ); params.gravity = Gravity.BOTTOM; params.screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL; // Adjust brightness as needed
Key Flag Explanations:
- Removed
FLAG_NOT_FOCUSABLE: This allows yourEditTextto request focus and trigger the IME. FLAG_ALLOW_LOCK_WHILE_SCREEN_ON: Ensures your UI stays visible even if the lock screen is active (no auto-dismiss).FLAG_NOT_TOUCH_MODAL: Lets users interact with the lock screen behind your UI if needed (optional, but improves UX).
Step 3: Create and Add the Editable UI
Now initialize your EditText with focusable properties, then add it to the WindowManager from your Service:
// Initialize EditText with IME support EditText inputField = new EditText(this); inputField.setHint("Type here..."); inputField.setTextColor(ContextCompat.getColor(this, android.R.color.white)); inputField.setTextSize(24f); inputField.setInputType(InputType.TYPE_CLASS_TEXT); // Ensure it can gain focus inputField.setFocusable(true); inputField.setFocusableInTouchMode(true); // Get WindowManager instance WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); windowManager.addView(inputField, params); // Force show the keyboard once the view is attached to the window inputField.post(() -> { InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); imm.showSoftInput(inputField, InputMethodManager.SHOW_IMPLICIT); });
Fixes for Your Transparent Activity Approach (Alternative)
If you prefer using an Activity instead, you missed a few critical flags in your Activity's code. Add these in onCreate() before setContentView():
getWindow().addFlags( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD // Optional: bypasses swipe lock (not PIN/password) );
Also, update your manifest to use the non-deprecated attribute for lock screen visibility:
<activity android:name=".OverlayActivity" android:theme="@style/TransparentActivity" android:showWhenLocked="true" android:excludeFromRecents="true" />
Critical Notes
- Foreground Service Requirement: On Android 8.0+, background services can't show overlays. Make your Service a foreground service by showing a persistent notification:
Notification notification = new NotificationCompat.Builder(this, "overlay_channel") .setContentTitle("Overlay Active") .setSmallIcon(R.drawable.ic_notification) .build(); startForeground(1, notification); - Cleanup: Always remove the view from
WindowManagerwhen your Service is destroyed to avoid memory leaks:@Override public void onDestroy() { super.onDestroy(); if (inputField != null && windowManager != null) { windowManager.removeView(inputField); } } - Android 10+ Edge Cases: For PIN/password locks,
TYPE_APPLICATION_OVERLAYshould work, but if you encounter issues, consider usingTYPE_ACCESSIBILITY_OVERLAY(requires enabling an accessibility service for your app, which has stricter Play Store guidelines).
Content of the question comes from Stack Exchange, asked by Udi Oshi

