Android OnClickListener inside services - android

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

Related

Unable to use intent extra from onStartCommand

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);
}

Window Manager click issue

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

Android : How to set onCick listener to custom layout which is displayed using the WINDOW_SERVICE as floating window?

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

Window manager not showing window on the top

In an android application I have to show an internal notification that comes over the top of every screen in my app . I have used WindowManager. But it doesn't seem to work as expected. Sometimes I see the first notification but the second is not shown though when debugged ,step by step execution of the following method is visible. Can't figure out why is this happening. Help!!
public void addNotification(String message, Bundle bundle) {
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
lp.gravity = Gravity.END | Gravity.BOTTOM;
lp.x = getResources().getInteger(R.integer.notification_side_margin);
lp.y = getResources().getInteger(R.integer.notification_side_margin);
// Initialise container view first in which every notification is to be
// added.
if (notificationConatinerView == null) {
notificationConatinerView = getLayoutInflater().inflate(
R.layout.custom_notification_main_layout, null);
notificationContainer = (LinearLayout) notificationConatinerView
.findViewById(R.id.notification_container);
notificationContainer.setPadding(
(int) getResources().getDimension(R.dimen.mini_margin),
(int) getResources().getDimension(R.dimen.mini_margin),
(int) getResources().getDimension(R.dimen.mini_margin),
(int) getResources().getDimension(R.dimen.mini_margin));
windowManager.addView(notificationConatinerView, lp);
// Add that container to the window manager
windowManager.updateViewLayout(notificationConatinerView, lp);
}
final View view = getLayoutInflater().inflate(
R.layout.notification_custom, null);
view.setTag(bundle);
view.setId(notificationContainer.getChildCount());
view.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Bundle bundle = (Bundle) v.getTag();
setClickForNotifications(bundle);
}
});
final ImageView crossImage = (ImageView) view
.findViewById(R.id.notification_cross);
crossImage.setTag(view);
TextView messageTextView = (TextView) view
.findViewById(R.id.message_text);
messageTextView.setText(message);
crossImage.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if (notificationContainer.getChildCount() == 1) {
showNotificationExitingView(v);
} else {
if (!isFinishing())
notificationContainer.removeView((View) crossImage
.getTag());
}
}
});
LinearLayout.LayoutParams childLP = new LinearLayout.LayoutParams(
(int) getResources().getDimension(
R.dimen.notification_view_width),
RelativeLayout.LayoutParams.WRAP_CONTENT);
if (notificationContainer.getChildCount() == getResources().getInteger(
R.integer.no_of_notifications)) {
notificationContainer.removeViewAt(notificationContainer
.getChildCount() - 1);
}
notificationContainer.addView(view, 0, childLP);
notificationContainer.updateViewLayout(view, childLP);
Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
#Override
public void run() {
if (notificationContainer.getChildCount() == 1) {
showNotificationExitingView(view);
} else {
if (!isFinishing())
notificationContainer.removeView(view);
}
}
}, 10000);
try {
windowManager.updateViewLayout(notificationConatinerView, lp);
} catch (Exception e) {
windowManager.addView(notificationConatinerView, lp);
windowManager.updateViewLayout(notificationConatinerView, lp);
}
if (notificationContainer.getChildCount() == 1) {
showNotificationEnteringAnimation();
}
}
Thanks!!
use
windowManager = (WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE);
instead of
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);

WindowManager.removeView() gives IllegalStateException

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);
}
});
}
}

Categories

Resources