Below code snippet only shows view but click on buttons not working. I have tried all solution but nothing seems to work. Another service have same code fragment with different layout works.
public int onStartCommand(final Intent intent, int flags, int startId) {
LayoutInflater inflater = (LayoutInflater)getApplicationContext().getSystemService(LAYOUT_INFLATER_SERVICE);
if (inflater!=null)
v = inflater.inflate(R.layout.layout_accept_sos, null);
close = v.findViewById(R.id.close);
close.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
onDestroy();
}
});
getDirection = v.findViewById(R.id.getDirection);
getDirection.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent1=new Intent();
intent1.setAction("open_map");
sendBroadcast(intent1);
// onDestroy();
}
});
params = new WindowManager.LayoutParams(LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, LayoutParams.FLAG_ALT_FOCUSABLE_IM | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT);
params.gravity = Gravity.LEFT | Gravity.TOP;
params.x = 0;
params.y = 0;
wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
wm.addView(v, params);
return START_STICKY;
}
You need to use WindowManager.FLAG_NOT_FOCUSABLE to make it clickable.
params = new WindowManager.LayoutParams(LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
More description available at https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_NOT_FOCUSABLE
Related
I am trying to make a Android app with a service (Floating widget). Since I am not a pro-programmer, I did not use touch listener to change position of that widget for lot of reasons. But I want user to have options to change position (some preferred locations only) of that widget, and that options will be available in an activity which invoked the service. I am passing data as intent extra from my activity to service, which is to be obtained from service onStartCommand(). The problem I am facing now- I am unable to use data obtained from onStartCommand() in onCreate(). Seems the service is created before onStartCommand() is called and I am getting null pointer exception as some of my variables are not obtaining values from onStartCommand(). I have checked, that these variables are getting values when I use any clickable objects (e.g: press any button view in service), I used a dummy toast for this.
Please share your valuable opinion on how to overcome this problem.
public class MainFloatingWidget extends Service {
private WindowManager windowManager;
private View myFloatingView, myCollapsedView, myExpandedView;
private WindowManager.LayoutParams params;
private String position;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
myFloatingView = LayoutInflater.from(this).inflate(R.layout.layout_main_floating_widget, null);
params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
windowManager.addView(myFloatingView, params);
myCollapsedView = myFloatingView.findViewById(R.id.collapsedViewMainService);
myExpandedView = myFloatingView.findViewById(R.id.expandedViewMainService);
myCollapsedView.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
myCollapsedView.setVisibility(View.GONE);
myExpandedView.setVisibility(View.VISIBLE);
return true;
}
});
myExpandedView.findViewById(R.id.buttonBack).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
myCollapsedView.setVisibility(View.VISIBLE);
myExpandedView.setVisibility(View.GONE);
}
});
myExpandedView.findViewById(R.id.buttonClose).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
windowManager.removeView(myFloatingView);
stopSelf();
}
});
if(position.equals("Right-Middle")){
params.gravity = Gravity.END | Gravity.CENTER;
}else if(position.equals("Right-Top")){
params.gravity = Gravity.END | Gravity.TOP;
}else if(position.equals("Right-Bottom")){
params.gravity = Gravity.END | Gravity.BOTTOM;
}else if(position.equals("Left-Middle")){
params.gravity = Gravity.START | Gravity.CENTER;
}else if(position.equals("Left-Top")){
params.gravity = Gravity.START | Gravity.TOP;
}else if(position.equals("Left-Bottom")){
params.gravity = Gravity.START | Gravity.BOTTOM;
}else{
params.gravity = Gravity.CENTER;
}
windowManager.updateViewLayout(myFloatingView, params);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
position = (String) intent.getExtras().get("POSITION");
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
onCreate will call before onStartCommand and only call one time when Service init so you should move your code handle position to inside onStartCommand
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
position = (String) intent.getExtras().get("POSITION");
if(position.equals("Right-Middle")){
params.gravity = Gravity.END | Gravity.CENTER;
}else if(position.equals("Right-Top")){
params.gravity = Gravity.END | Gravity.TOP;
}else if(position.equals("Right-Bottom")){
params.gravity = Gravity.END | Gravity.BOTTOM;
}else if(position.equals("Left-Middle")){
params.gravity = Gravity.START | Gravity.CENTER;
}else if(position.equals("Left-Top")){
params.gravity = Gravity.START | Gravity.TOP;
}else if(position.equals("Left-Bottom")){
params.gravity = Gravity.START | Gravity.BOTTOM;
}else{
params.gravity = Gravity.CENTER;
}
windowManager.updateViewLayout(myFloatingView, params);
return super.onStartCommand(intent, flags, startId);
}
ImageView click is not working on custom layout creatd in android service.
public class CallService extends Service {
String incomingnumber;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
incomingnumber = intent.getExtras().getString("incomingnumber");
System.out.println("=== onStartCommand incomingnumber : " + incomingnumber);
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onCreate() {
super.onCreate();
final Context context = getApplicationContext();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewGroup mView = (ViewGroup) inflater.inflate(R.layout.testactivity, null);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
ImageView imgCallPick = mView.findViewById(R.id.imgCallPick);
ImageView imgCaller = mView.findViewById(R.id.imgCaller);
imgCaller.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
System.out.println("===== imgCaller");
return false;
}
});
wm.addView(mView, params);
} }
i just create custom layout in service, the layout contain a diff view but the Imageview click not working. is there any solution for that, then help me.
Thanks
From this answer: Android - ImageView On Click
Add in your xml layout:
android:clickable="true"
This issue is due to use of deprecated param
WindowManager.LayoutParams.TYPE_PHONE
For getting touch events
Use this if you want a colored background
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.RGB_565);
Use this if you want a transparent background
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.TRANSPARENT);
Everything else remains same :)
In service for displaying custom view over all windows I need to set onClick listener.
#Override public void onCreate() {
super.onCreate();
mContext = this;
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
LinearLayout parent = (LinearLayout) inflater.inflate(R.layout.result_layout,
null);
// Here i need to add onClick listener
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.LEFT;
params.x = 0;
params.y = 100;
windowManager.addView(parent, params);
}
I tried to create button lister from inflater but without luck. What is the right approach to set click event listener for selected button by button ID?
Many thanks for any advice.
Resolved using the following code which is works in the service well:
#Override public void onCreate() {
super.onCreate();
mContext = this;
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
final LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mParentLayout = (LinearLayout) inflater.inflate(R.layout.result_layout,
null);
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.LEFT;
params.x = 0;
params.y = 100;
windowManager.addView(mParentLayout, params);
Button b = (Button) mParentLayout.findViewById(R.id.closeButton);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
windowManager.removeView(mParentLayout);
}
});
}
Inspired from:
Could not get Touch event for TYPE_SYSTEM_OVERLAY
Android can play tricks on what you think might work, but doesn't.
First, What I typically do is from onCreate() I place a call to:
InitializePage(); where I then put all my initialize code. It's just my style.
Then in my InitializePage() function I initialize the button, then enter the OnClickListener. I use Android Studio with Intellisense so it writes the code for me....
mSendButton = (TextView)findViewById(R.id.send_button1);
mSendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v)
{.....
});
It should be that easy. Good luck
I'm trying to create an image which is on top of all windows with android services and this is onCreate method:
#Override
public void onCreate() {
super.onCreate();
mWindowsManger = (WindowManager) getSystemService(WINDOW_SERVICE);
mFloatingImage = new ImageView(this);
mFloatingImage.setImageResource(R.mipmap.ic_launcher);
mFloatingImage.setAlpha(0.5f);
mParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
mParams.gravity = Gravity.TOP | Gravity.LEFT;
mParams.x = 0;
mParams.y = 100;
mFloatingImage.setClickable(true);
mFloatingImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.print("clicked");
}
});
mWindowsManger.addView(mFloatingButtonImage, mParams);
}
My problem is OnClickListener not working instead OnTouchListener works .
Is there any way to implement OnClikListener in services ?
Do this:
#Override
public void onCreate() {
super.onCreate();
mWindowsManger = (WindowManager) getSystemService(WINDOW_SERVICE);
mFloatingImage = new ImageView(this);
mFloatingImage.setImageResource(R.mipmap.ic_launcher);
mFloatingImage.setAlpha(0.5f);
mParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
mParams.gravity = Gravity.TOP | Gravity.LEFT;
mParams.x = 0;
mParams.y = 100;
mFloatingImage.setClickable(true);
mWindowsManger.addView(mFloatingButtonImage, mParams);
mFloatingImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.print("clicked");
}
});
}
BUT I DO THIS RIGHT NOW IT WORKS FOR ME:
rl = (RelativeLayout) findViewById(R.id.rl);
b = (Button) findViewById(R.id.button1);
img = new ImageView(MainActivity.this);
img.setImageResource(R.drawable.ic_launcher);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
(int) LayoutParams.WRAP_CONTENT, (int) LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
img.setLayoutParams(params);
rl.addView(img);
img.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Toast.makeText(getBaseContext(), "Image Clicked",
Toast.LENGTH_SHORT).show();
}
});
Abhishek Das have given good answer. My answer is subset of his answer
Just you need to call :
mWindowsManger.addView(mFloatingButtonImage, mParams);
first and then :
mFloatingImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
System.out.print("clicked");
}
});
Before adding view to view hierarchy, the click listener may not work
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);
}
});
}
}