Softkeyboard does not appear when a Screenoverlay is active - android

I'm using a transparent screenoverlay to detect when a user long presses the power key of their phone (or rather, when the shutdown option dialog appears), this is working fine.
Unfortunately, when this screenoverlay is active, the soft keyboard stops appearing and that is a problem for me. How can I prevent that?
The code I'm using is heavily based on this: Detect power button long press
public void warnOnShutdown() {
if (Settings.canDrawOverlays(this)) {
LinearLayout linearLayout = new LinearLayout(getApplicationContext()) {
public void onCloseSystemDialogs(String reason) {
if ("globalactions".equals(reason)) {
AntitheftStateManager.setShuttingDown(AntitheftService.this, true);
}
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
return super.dispatchKeyEvent(event);
}
};
linearLayout.setFocusable(true);
View view = LayoutInflater.from(this).inflate(R.layout.system_overlay, linearLayout);
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
//params
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
100,
100,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.CENTER_VERTICAL;
windowManager.addView(view, params);
}
}
Layout:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="1dp"
android:layout_height="1dp"
android:orientation="vertical">
</LinearLayout>
Edit:
I should probably mention that the LinearLayout is attached to the window manager from a service, that means that the keyboard is not just blocked for my app, it's blocked for the whole phone as long as the service is running.

That's what happens when someone elses code is taken at face value. Turns out that changing the type from TYPE_SYSTEM_ALERT to TYPE_SYSTEM_OVERLAY solved my problem.
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
100,
100,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,
PixelFormat.TRANSLUCENT);

Related

Cannot intercept touch on overlay service

I am trying to block touch on a device using service and a transparent overlay.
The code seems to work fine on Android Oreo but doesn't work properly on devices running Android version below Oreo:
private void setWindowParams(){
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
} else {
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
}
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
FrameLayout noTouchUi = new FrameLayout(this);
wm.addView(noTouchUi,params);
}
Here I setup a FrameLayout noTouchUi to intercept touch as an overlay using service using onTouchListener
noTouchUi.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d(TAG,"touch event");
return true;
}
});
This works properly on Android 8, but doesn't work on Android 7, the overlay shows up properly, but the items behind overlay gets clicked. What I want to do is block that click.
Change the type from:
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY
to:
WindowManager.LayoutParams.TYPE_PHONE
and remove flags:
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
and:
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH

Android: Request focus on view (WebView) added via WindowManager

I am showing a webView as an alertDialog from a service when my app is not running on foreground, therefore, My webView is attached to the screen via WindowManager.addView() method.
The webView has an input field which I want to be accessible by the user. Unfortunately, when the user clicks on the input field, it is not showing the keyboard for users to allow input.
My webView is inside a cardView who's params are as follows:
public WindowManager.LayoutParams getParamsForOpenWebView() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.START | Gravity.TOP;
params.x = left;
params.y = top;
return params;
} else {
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.START | Gravity.TOP;
params.x = left;
params.y = 200;
return params;
}
}
If I connect the phone to my laptop and use the laptop keyboard to add inputs to the input field, it works fine but it's just that the keyboard on the phone does not pop-up.
Also, the input is inside the webView therefore I cannot use View.requestFocus() to get focus unlike in case of an EditText.
I would really appreciate any help regarding how to request focus to the webView to allow inputs.
Found an answer to the question myself after a while.
I tried a lot of combinations of different flags but none worked, unless I tried
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
These flags gave the results I wanted and hope it helps someone who goes through the same.

Show UI (Activity/WindowManager) over lock screen & support in Oreo

My main goal is to show UI (With EditText, so IME support) Over the lock screen (No matter if there's PIN/Code or simple lock screen).
I know that WhatsApp application is doing it (Settings > Notification > Always show popup) so there's a solution for that.
The UI must be initialized from Service.
The view is a simple textview:
textview = new TextView(this);
textview.setText("Hello There!");
textview.setTextColor(ContextCompat.getColor(this,
android.R.color.white));
textview.setTextSize(32f);
I've tried several ways so far:
(In order to reproduce like whats app i'm doing everything when screen off receiver called)
Using WindowManager
WindowManager Params:
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.BOTTOM;
params.screenBrightness = 0;
Result: TextView is shown only after we unlock the device
Using Transparent activity
Activity style:
true
#android:color/transparent
#null
true
true
false
Also, has android:showOnLockScreen="true" attribute
Result: TextView is shown only after we unlock the device
Any other suggestions?
Thanks.
Add this in onCreate() of your Activity:
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
}

BACK button callback in Overlay window in Android

I'm showing a overlay window from service in my app. I want to hide the window when press back button. So to get the back button event I do the following code
class MyView extends MyLayout{
public MyView(Context context){
super(context);
LayoutInflater.from(context).inflater(R.layout.my_view,this);
}
}
Class MyLayout extends FrameLayout{
public MyLayout(Context context){
super(context);
}
#Override
public boolean dispatchKeyEvent(KeyEvent event) {
Log.e("key event", "" + event.getKeyCode());
return super.dispatchKeyEvent(event);
}
}
//service code
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
| WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS |
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
PixelFormat.TRANSLUCENT);
final MyView myview = new MyView(this);
windowManager.addView(myview,param);
But dispatchKeyEvent method never called on back button pressed. I Googled and found out this is the way to capture the back button event. Somehow it's not working in my case. What am I missing ?
If you just want to capture the back button pressed event use:
#override
public void onBackPressed(){
// Do what you need done here
// ... or pass super.onBackPressed();
}
Real problem is the window params. I need to only WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH flags which prevent other app to get key events. So the correct code is following
//service code
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS |
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION | WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS,
PixelFormat.TRANSLUCENT);

Block touch from a service

Is there a way to block touch on ANY application from a service? I've been thinking about getWindow(), but that is impossible in service. Also, I've been thinking about getting current activity and then use getWindow(). I hope you get the point of what am I tried to achieve.
Thanks to David Medenjak I have managed to solve the problem. This solution is working on Android APIs below 23 and it's going to make the screen black and block touches until you longpress on the screen.
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
ImageView black = new ImageView(this);
black.setImageResource(R.drawable.black);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP | Gravity.LEFT;
params.x = 0;
params.y = 0;
windowManager.addView(black, params);
black.getLayoutParams().height = windowManager.getDefaultDisplay().getHeight();
black.getLayoutParams().width = windowManager.getDefaultDisplay().getWidth();
black.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
return false;
}
});

Categories

Resources