I have a window manager set up and it has the flag FLAG_NOT_FOCUSABLE which means it will not get the focus of key events. Is there anyway to reverse this upon a click for example? For example, if I click on a button, I want the window to be clickable. How could I do this?
Simply update the window manager with the new parameters.
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//remove FLAG_NOT_FOCUSABLE
params.flags = params.flags & ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
//update the view
windowManager.updateViewLayout(view, params);
}
});
Related
I have implemented chat head kind of pop up for my application using service. And I have used edit text inside that.
But problem is that when I click on edit text only cursor is visible and keyboard is not coming up. And not even able to select or copy paste the text inside that edit text. Any help? Thanks
I found solution to my problem.
I was using the following code earlier:-
Global variables:-
private WindowManager mWindowManager;
WindowManager.LayoutParams params;
Then in onCreate of Service
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
//Add the view to the window.
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
Problem was with FLAG_NOT_FOCUSABLE, use FLAG_NOT_TOUCH_MODAL instead.
But now again problem was that though I was able to get the keyboard with my floatingView but keypad was not coming for other apps, even back button stopped working.
So to fix this I used button on Floating UI which toggles between enabling keypad on floating UI and disabling that so that back button and keypad works for other apps.
I used the following code for the same:-
private void enableKeyPadInput(Boolean enable) {
mWindowManager.removeViewImmediate(mFloatingView);
if (enable) {
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
} else {
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
}
mWindowManager.addView(mFloatingView, params);
}
If true is passed to this method then keypad starts working. If false is passed then other apps starts working.
This is my workaround for the problem. Is there any other way to achieve the same which is better than this?
thank #Narendra Jadon
this maybe better
private void enableKeyPadInput(Boolean enable) {
//mWindowManager.removeView(mFloatingView);
if (enable) {
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
} else {
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
}
mWindowManager.updateViewLayout(mFloatingView,params);
//mWindowManager.addView(mFloatingView, params);
}
I am adding a textview to Window using the following code
public static void addViewToWindow(Activity activity, View view, WindowManager.LayoutParams params)
{
WindowManager windowManager = (WindowManager)activity.getSystemService(Context.WINDOW_SERVICE);
windowManager.addView(view, params);
}
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_PANEL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.OPAQUE);
params.gravity = Gravity.BOTTOM;
params.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
addViewToWindow(myActivity, myEditText, params);
But I am not able to long press on the EditText to let the user copy/paste. As soon as I change the orientation of the device to landscape, the EditText covers the entire screen and I am able to copy/paste by long press. I am not able to make out what I am doing wrong.
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);
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;
}
});
I have an activity that creates a view of type TYPE_SYSTEM_ALERT and I set a touch listener to the view. Is it possible to record the touch but still send the touch event to other views (example: to a widget from my home screen)?
Here is my code:
public class TestGestures extends Activity implements View.OnTouchListener {
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final WindowManager.LayoutParams param=new WindowManager.LayoutParams();
param.flags=WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
final View view=findViewById(R.id.view1);
final ViewGroup parent=(ViewGroup)view.getParent();
if(parent!=null)
parent.removeView(view);
param.format= PixelFormat.RGBA_8888;
param.type=WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
param.gravity= Gravity.TOP|Gravity.LEFT;
param.width=view.getLayoutParams().width;
param.height=view.getLayoutParams().height;
//view.setBackgroundColor(android.R.color.white);
final WindowManager wmgr=(WindowManager)getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
wmgr.addView(view,param);
view.setOnTouchListener(this);
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return false;
}
}
When I'm in the home screen, the touch events are not sent to the widgets
You'll have to play around with the parameters that you're using to setup your WindowManager.LayoutParams. For example, the code below will make the touch events be delivered to the Activity (or View) which is below the view that you just created:
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
On the other hand, if you change TYPE_SYSTEM_OVERLAY to TYPE_SYSTEM_PHONE, the input events will be delivered to the View that is on top of the other ones:
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
So, in your case, since you want the input events to be delivered to the views below, try setting the TYPE_SYSTEM_OVERLAY flag.