I am running a background service to detect MotionEvent.ACTION_DOWN in Android 5.0. I used bellow code and it can detect my touch event but i cannot touch other apps. How can I fix it? If you have a better solution, please give me. Thank all.
public class TouchServiceListener extends Service implements OnTouchListener {
private WindowManager mWindowManager;
// linear layout will use to detect touch event
private LinearLayout touchLayout;
#Override
public void onCreate() {
super.onCreate();
touchLayout = new LinearLayout(this);
// set layout width 30 px and height is equal to full screen
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
touchLayout.setLayoutParams(lp);
// set color if you want layout visible on screen
touchLayout.setBackgroundColor(Color.CYAN);
// set on touch listener
touchLayout.setOnTouchListener(this);
// fetch window manager object
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
// set layout parameter of window manager
WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT, // width of layout 30 px
WindowManager.LayoutParams.MATCH_PARENT, // height is equal to full screen
WindowManager.LayoutParams.TYPE_PHONE, // Type Ohone, These are non-application windows providing user interaction with the phone (in particular incoming calls).
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, // this window won't ever get key input focus
PixelFormat.TRANSLUCENT);
mParams.gravity = Gravity.LEFT | Gravity.TOP;
Log.i(TAG, "add View");
mWindowManager.addView(touchLayout, mParams);
}
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if(motionEvent.getAction() == MotionEvent.ACTION_UP|motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
Log.d(TAG, "Touch me");
}
return true;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Manifest
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
First of all make your Layout according to overlay.you are setting width and height match_parent which is cover whole screen so that you are not accessing application which is outside of your application.
package anew.mikka.myapplication;
import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnTouchListener;
import android.widget.Button;
import android.widget.Toast;
public class max extends Service implements View.OnTouchListener {
Button mButton;
#Override
public IBinder
onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
//mView = new HUDView(this);
mButton = new Button(this);
mButton.setText("Overlay button");
mButton.setOnTouchListener(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.BOTTOM | Gravity.RIGHT;
params.setTitle("Load Average");
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mButton, params);
}
#Override
public void onDestroy() {
super.onDestroy();
if(mButton != null)
{
((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(mButton);
mButton = null;
}
}
#Override
public boolean onTouch(View v, MotionEvent event) {
Toast.makeText(this,"Overlay button event", Toast.LENGTH_SHORT).show();
return false;
}
}
I'm trying to create a custom chatHead which would show only when a particular app is open. (e.g. Messenger or WhatsApp). And would be destroyed when that app has been closed.
Here's my code-
#Override
public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
chatHead = new ImageView(this);
chatHead.setImageResource(R.drawable.view_icon);
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);
params.gravity = Gravity.TOP | Gravity.START;
params.x = 0;
params.y = 100;
windowManager.addView(chatHead, params);
getForeground();
chatHead.setOnClickListener(new View.OnClickListener() {
/*.....
.....
ClickListener implemented
.....
.....
*/
});
}
Here, in the onCreate(), I'm calling the getForeground() method, which gets the current activity in the foreground
public String getForeground() {
final ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
String foreground = am.getRunningTasks(1).get(0).topActivity.getPackageName();
if (foreground.equals("com.whatsapp")) {
if (chatHead==null)
onResume();
}
else
onDestroy();
new Thread() {
#Override
public void run() {
getForeground();
}
}.start();
return foreground;
}
Where, onResume() is-
public void onResume() {
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);
params.gravity = Gravity.TOP | Gravity.START;
params.x = 0;
params.y = 100;
windowManager.addView(chatHead,params);
}
And onDestroy() is-
#Override
public void onDestroy() {
super.onDestroy();
if (chatHead != null)
windowManager.removeView(chatHead);
else
chatHead=null;
}
However, it shows an IllegalStateException as follows-
java.lang.IllegalArgumentException: View=android.widget.ImageView{41f07a28 V.ED..C. ......ID 0,0-93,99} not attached to window manager
at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.java:370)
at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java:299)
at android.view.WindowManagerImpl.removeView(WindowManagerImpl.java:79)
at automated.whatsapp.com.automatedtest.ChatHeadService.onDestroy(ChatHeadService.java:172)
at automated.whatsapp.com.automatedtest.ChatHeadService.getForeground(ChatHeadService.java:188)
at automated.whatsapp.com.automatedtest.ChatHeadService$3.run(ChatHeadService.java:194)
So, basically, it says that the chatHead is not attached to the WindowManager. How do I correct this error?
You can use try-catch around your window manager like this
try{
WindowManager?.removeView(view);
}catch(e:Exception){
Log.e(debug_tag, "view not found");
}
or can check windowtoken of view exist
if (view?.windowToken!=null) {
WindowManager?.removeView(view);
}
because when your view is not added or remove view later your windowmanager make a new exception
Not sure if this can help you but this is what I did:
#Override
protected void onUserLeaveHint() {
if (this.chatHead != null) {
this.runOnUiThread(new Runnable() {
#Override
public void run() {
((WindowManager) getApplicationContext().getSystemService(Service.WINDOW_SERVICE)).removeView(chatHead);
}
});
}
}
I'm trying to create an always-op-top button/clickable-image
which stays on top of all the windows all the time.
The proof of
concept is
here - Smart Taskbar (on AppBrain)
and here V1.4.0 Sidebar style SWKey - Button savior (on xda-developers)
I have been successful and have a running service now. The service
displays some text on top left corner of screen all the time while
user can freely interact with rest of apps in normal manner.
What I'm
doing is subclass ViewGroup and add it to root window manager with
flag TYPE_SYSTEM_OVERLAY. Now I want to add a button/clickable-image
in place of this text which can receive touch events on itself. I
tried overriding "onTouchEvent" for the whole ViewGroup but it does
not receive any event.
How can I receive events only on certain parts
of my always-on-top view group? Kindly suggest.
public class HUD extends Service {
HUDView mView;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();
mView = new HUDView(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
0,
// WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
// | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
params.setTitle("Load Average");
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mView, params);
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(getBaseContext(),"onDestroy", Toast.LENGTH_LONG).show();
if(mView != null)
{
((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(mView);
mView = null;
}
}
}
class HUDView extends ViewGroup {
private Paint mLoadPaint;
public HUDView(Context context) {
super(context);
Toast.makeText(getContext(),"HUDView", Toast.LENGTH_LONG).show();
mLoadPaint = new Paint();
mLoadPaint.setAntiAlias(true);
mLoadPaint.setTextSize(10);
mLoadPaint.setARGB(255, 255, 0, 0);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawText("Hello World", 5, 15, mLoadPaint);
}
#Override
protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
}
#Override
public boolean onTouchEvent(MotionEvent event) {
//return super.onTouchEvent(event);
Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();
return true;
}
}
This might be a stupid solution. But it works. If you can improve it, please let me know.
OnCreate of your Service: I have used WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH flag. This is the only change in service.
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();
mView = new HUDView(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
params.setTitle("Load Average");
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mView, params);
}
Now, you will start getting each and every click event. So, you need to rectify in your event handler.
In your ViewGroup touch event
#Override
public boolean onTouchEvent(MotionEvent event) {
// ATTENTION: GET THE X,Y OF EVENT FROM THE PARAMETER
// THEN CHECK IF THAT IS INSIDE YOUR DESIRED AREA
Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();
return true;
}
Also you may need to add this permission to your manifest:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Following #Sam Lu's answer,
Indeed Android 4.x blocks certain types from listening to outside touch events, but some types, such as TYPE_SYSTEM_ALERT, still do the job.
Example
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
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View myView = inflater.inflate(R.layout.my_view, null);
myView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Log.d(TAG, "touch me");
return true;
}
});
// Add layout to window manager
wm.addView(myView, params);
Permissions
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
Starting with Android 4.x, Android team fixed a potential
security problem by adding a new function adjustWindowParamsLw() in which it
will add FLAG_NOT_FOCUSABLE, FLAG_NOT_TOUCHABLE and remove FLAG_WATCH_OUTSIDE_TOUCH flags for TYPE_SYSTEM_OVERLAY windows.
That is, a TYPE_SYSTEM_OVERLAY window won't receive any touch event on ICS platform and, of course, to use TYPE_SYSTEM_OVERLAY is not a workable solution for ICS and future devices.
I'm one of the developers of the Tooleap SDK. We also provide a way for developers to display always on top windows and buttons, and and we have dealt with a similar situation.
One problem the answers here haven't addressed is that of the Android "Secured Buttons".
Secured buttons have the filterTouchesWhenObscured property which means they can't be interacted with, if placed under a window, even if that window does not receive any touches. Quoting the Android documentation:
Specifies whether to filter touches when the view's window is obscured
by another visible window. When set to true, the view will not receive
touches whenever a toast, dialog or other window appears above the
view's window. Refer to the {#link android.view.View} security
documentation for more details.
An example of such a button is the install button when you try to install third party apks. Any app can display such a button if adding to the view layout the following line:
android:filterTouchesWhenObscured="true"
If you display an always-on-top window over a "Secured Button", so all the secured button parts that are covered by an overlay will not handle any touches, even if that overlay is not clickable. So if you are planing to display such a window, you should provide a way for the user to move it or dismiss it.
And if a part of your overlay is transparent, take into account that your user might be confused why is a certain button in the underlying app is not working for him suddenly.
WORKING ALWAYS ON TOP IMAGE BUTTON
first of all sorry for my english
i edit your codes and make working image button that listens his touch event
do not give touch control to his background elements.
also it gives touch listeners to out of other elements
button alingments are bottom and left
you can chage alingments but you need to chages cordinats in touch event in the if element
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.os.IBinder;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Toast;
public class HepUstte extends Service {
HUDView mView;
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();
final Bitmap kangoo = BitmapFactory.decodeResource(getResources(),
R.drawable.logo_l);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
kangoo.getWidth(),
kangoo.getHeight(),
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.BOTTOM;
params.setTitle("Load Average");
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
mView = new HUDView(this,kangoo);
mView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View arg0, MotionEvent arg1) {
// TODO Auto-generated method stub
//Log.e("kordinatlar", arg1.getX()+":"+arg1.getY()+":"+display.getHeight()+":"+kangoo.getHeight());
if(arg1.getX()<kangoo.getWidth() & arg1.getY()>0)
{
Log.d("tıklandı", "touch me");
}
return false;
}
});
wm.addView(mView, params);
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
#SuppressLint("DrawAllocation")
class HUDView extends ViewGroup {
Bitmap kangoo;
public HUDView(Context context,Bitmap kangoo) {
super(context);
this.kangoo=kangoo;
}
protected void onDraw(Canvas canvas) {
//super.onDraw(canvas);
// delete below line if you want transparent back color, but to understand the sizes use back color
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(kangoo,0 , 0, null);
//canvas.drawText("Hello World", 5, 15, mLoadPaint);
}
protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {
}
public boolean onTouchEvent(MotionEvent event) {
//return super.onTouchEvent(event);
// Toast.makeText(getContext(),"onTouchEvent", Toast.LENGTH_LONG).show();
return true;
}
}
The TYPE_SYSTEM_OVERLAY constant was deprecated since API level 26.
Use TYPE_APPLICATION_OVERLAY instead.
For users below and above Android 8:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
LAYOUT_FLAG = WindowManager.LayoutParams.TYPE_PHONE;
}
Try this. Works fine in ICS.
If You want to stop service simply click the notification generated in statusbar.
public class HUD extends Service
{
protected boolean foreground = false;
protected boolean cancelNotification = false;
private Notification notification;
private View myView;
protected int id = 0;
private WindowManager wm;
private WindowManager.LayoutParams params;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
// System.exit(0);
Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_SHORT).show();
params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
params.gravity=Gravity.TOP|Gravity.LEFT;
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
inflateview();
foregroundNotification(1);
//moveToForeground(1,n,true);
}
#Override
public void onDestroy() {
super.onDestroy();
((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(0);
Toast.makeText(getBaseContext(),"onDestroy", Toast.LENGTH_SHORT).show();
if(myView != null)
{
((WindowManager) getSystemService(WINDOW_SERVICE)).removeView(myView);
myView = null;
}
}
protected Notification foregroundNotification(int notificationId)
{
notification = new Notification(R.drawable.ic_launcher, "my Notification", System.currentTimeMillis());
notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT | Notification.FLAG_ONLY_ALERT_ONCE;
notification.setLatestEventInfo(this, "my Notification", "my Notification", notificationIntent());
((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).notify(id, notification);
return notification;
}
private PendingIntent notificationIntent() {
Intent intent = new Intent(this, stopservice.class);
PendingIntent pending = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return pending;
}
public void inflateview()
{
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
myView = inflater.inflate(R.layout.activity_button, null);
myView.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
Toast.makeText(getBaseContext(),"onToasttt", Toast.LENGTH_SHORT).show();
return false;
}
});
// Add layout to window manager
wm.addView(myView, params);
}
}
UPDATE
Sample here
To create an overlay view, when setting up the LayoutParams DON'T set the type to TYPE_SYSTEM_OVERLAY.
Instead set it to TYPE_PHONE.
Use the following flags:
FLAG_NOT_TOUCH_MODAL
FLAG_WATCH_OUTSIDE_TOUCH
Actually, you can try WindowManager.LayoutParams.TYPE_SYSTEM_ERROR instead of TYPE_SYSTEM_OVERLAY. It may sound like a hack, but it let you display view on top of everything and still get touch events.
Found a library that does just that:
https://github.com/recruit-lifestyle/FloatingView
There's a sample project in the root folder. I ran it and it works as required. The background is clickable - even if it's another app.
Here is some simple solution,
All you need is to inflate XML layout just like you do on list adapters,
just make XML layout to inflate it.
Here is code that all you need.
public class HUD extends Service {
View mView;
LayoutInflater inflate;
TextView t;
Button b;
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(getBaseContext(),"onCreate", Toast.LENGTH_LONG).show();
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
Display display = wm.getDefaultDisplay(); get phone display size
int width = display.getWidth(); // deprecated - get phone display width
int height = display.getHeight(); // deprecated - get phone display height
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
width,
height,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.CENTER;
params.setTitle("Load Average");
inflate = (LayoutInflater) getBaseContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mView = inflate.inflate(R.layout.canvas, null);
b = (Button) mView.findViewById(R.id.button1);
t = (TextView) mView.findViewById(R.id.textView1);
b.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
t.setText("yes you click me ");
}
});
wm.addView(mView, params);
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
}
It uses permission "android.permission.SYSTEM_ALERT_WINDOW" full tutorial on this link : http://androidsrc.net/facebook-chat-like-floating-chat-heads/
This is an old Question but recently Android has a support for Bubbles. Bubbles are soon going to be launched but currently developers can start using them.They are designed to be an alternative to using SYSTEM_ALERT_WINDOW. Apps like (Facebook Messenger and MusiXMatch use the same concept).
Bubbles are created via the Notification API, you send your notification as normal. If you want it to bubble you need to attach some extra data to it. For more information about Bubbles you can go to the official Android Developer Guide on Bubbles.
Well try my code, atleast it gives you a string as overlay, you can very well replace it with a button or an image. You wont believe this is my first ever android app LOL. Anyways if you are more experienced with android apps than me, please try
changing parameters 2 and 3 in "new WindowManager.LayoutParams"
try some different event approach
If anyone still reading this thread and not able to get this working, I'm very sorry to tell you this way to intercept motion event is considered as bug and fix in android >=4.2.
The motion event you intercepted, although has action as ACTION_OUTSIDE, return 0 in getX
and getY. This means you can not see all the motion position on screen, nor can you do anything. I know the doc said It will get x and y, but the truth is it WILL NOT. It seems that this is to block key logger.
If anyone do have a workaround, please leave your comment.
ref:
Why does ACTION_OUTSIDE return 0 everytime on KitKat 4.4.2?
https://code.google.com/p/android/issues/detail?id=72746
by using service you can achieve this :
public class PopupService extends Service{
private static final String TAG = PopupService.class.getSimpleName();
WindowManager mWindowManager;
View mView;
String type ;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// registerOverlayReceiver();
type = intent.getStringExtra("type");
Utils.printLog("type = "+type);
showDialog(intent.getStringExtra("msg"));
return super.onStartCommand(intent, flags, startId);
}
private void showDialog(String aTitle)
{
if(type.equals("when screen is off") | type.equals("always"))
{
Utils.printLog("type = "+type);
PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
WakeLock mWakeLock = pm.newWakeLock((PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "YourServie");
mWakeLock.acquire();
mWakeLock.release();
}
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mView = View.inflate(getApplicationContext(), R.layout.dialog_popup_notification_received, null);
mView.setTag(TAG);
int top = getApplicationContext().getResources().getDisplayMetrics().heightPixels / 2;
LinearLayout dialog = (LinearLayout) mView.findViewById(R.id.pop_exit);
// android.widget.LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) dialog.getLayoutParams();
// lp.topMargin = top;
// lp.bottomMargin = top;
// mView.setLayoutParams(lp);
final EditText etMassage = (EditText) mView.findViewById(R.id.editTextInPopupMessageReceived);
ImageButton imageButtonSend = (ImageButton) mView.findViewById(R.id.imageButtonSendInPopupMessageReceived);
// lp = (LayoutParams) imageButton.getLayoutParams();
// lp.topMargin = top - 58;
// imageButton.setLayoutParams(lp);
imageButtonSend.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Utils.printLog("clicked");
// mView.setVisibility(View.INVISIBLE);
if(!etMassage.getText().toString().equals(""))
{
Utils.printLog("sent");
etMassage.setText("");
}
}
});
TextView close = (TextView) mView.findViewById(R.id.TextViewCloseInPopupMessageReceived);
close.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
hideDialog();
}
});
TextView view = (TextView) mView.findViewById(R.id.textviewViewInPopupMessageReceived);
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
hideDialog();
}
});
TextView message = (TextView) mView.findViewById(R.id.TextViewMessageInPopupMessageReceived);
message.setText(aTitle);
final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
// | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON ,
PixelFormat.RGBA_8888);
mView.setVisibility(View.VISIBLE);
mWindowManager.addView(mView, mLayoutParams);
mWindowManager.updateViewLayout(mView, mLayoutParams);
}
private void hideDialog(){
if(mView != null && mWindowManager != null){
mWindowManager.removeView(mView);
mView = null;
}
}
}
#Sarwar Erfan's answer does not work any longer as Android does not allow adding view with WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY to window to be touchable anymore not with even WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH.
I found solution to this problem. You can check it out in following question
When adding view to window with WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, it is not getting touch event
TYPE_SYSTEM_OVERLAY is deprecated and will give a permission denied error.
Use WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY instead.
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL might be what you're looking for.
Window flag: even when this window is focusable (its FLAG_NOT_FOCUSABLE is not set), allow any pointer events outside of the window to be sent to the windows behind it. Otherwise it will consume all pointer events itself, regardless of whether they are inside of the window.
Docs
Implement View.OnClickListener or View.onTouchListener to listen for touch events.