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);
Related
I want to show an overlay view at some specific bound in screen ( like Rect(30,60,200, 400)). My code always gives a fullscreen overlay view, not the desired rect with specific top left, width, height.
My layout file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#50018786"/>
</RelativeLayout>
Main Activity code:
public class MainActivity extends AppCompatActivity {
public static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE = 5469;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
Intent myIntent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(myIntent);
} else {
onAuthorizedOverlay();
}
}
private void onAuthorizedOverlay() {
Button button = findViewById(R.id.inflate_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT
);
// params.x = 30; // these code have no effect
// params.y = 60;
// params.width = 170;
// params.height = 340;
Rect r = new Rect(30,60,200, 400);
WindowManager windowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
LayoutInflater li = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
RelativeLayout mTopView = (RelativeLayout) li.inflate(R.layout.my_overlay, null);
windowManager.addView(mTopView, params);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) {
if (!Settings.canDrawOverlays(this)) {
// You don't have permission
} else {
// Do as per your logic
onAuthorizedOverlay();
}
}
}
}
I noticed that the commented code I made for params has no effect.
How can I show an overlay view at a certain rect?
You are not using mentioned rectangle anywhere.
Check this out.
private void onAuthorizedOverlay() {
Button button = findViewById(R.id.inflate_button);
button.setOnClickListener(view -> {
WindowManager windowManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
LayoutInflater li = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
RelativeLayout mTopView = (RelativeLayout) li.inflate(R.layout.my_overlay, null);
WindowManager.LayoutParams overlayParams = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
overlayParams.height = 100;
overlayParams.width = 200;
overlayParams.x = 300;
overlayParams.y = 400;
windowManager.addView(mTopView, overlayParams);
});
}
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
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);
}
});
}
}
I have a pop up that displays an image upon clicking a button. I got to display the pop up but the image is so small and I want it to occupy the 90% of the screen and add a close button to it.
Here is my code:
PopupWindow popUp;
LinearLayout layout;
TextView tv;
LayoutParams params;
ImageView imageView;
boolean click = true;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bmi);
popUp = new PopupWindow(this);
layout = new LinearLayout(this);
tv = new TextView(this);
imageView = new ImageView(this);
imageView.setImageResource(R.drawable.animalbite);
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
int fullScreenWidth = display.getWidth();
int dialogWidth = (int) (fullScreenWidth * 0.9);
WindowManager.LayoutParams params = getWindow().getAttributes();
params.height = LayoutParams.WRAP_CONTENT;
params.width = dialogWidth;
getWindow().setAttributes(params);
imageView.setLayoutParams(params);
//tv.setText("Hi this is a sample text for popup window");
layout.addView(imageView, params);
popUp.setContentView(layout);
Button ViewBmi = (Button) findViewById(R.id.ViewBmi);
ViewBmi.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (click) {
popUp.showAtLocation(layout, Gravity.CENTER, 10 ,10);
click = false;
} else {
popUp.dismiss();
click = true;
}
}
});
}
Here is the display:
ANy ideas?
Try this...
PopupWindow popUp;
LinearLayout layout;
TextView tv;
LayoutParams params,params2;
ImageView imageView;
boolean click = true;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Display display = getWindowManager().getDefaultDisplay();
final int height = (display.getHeight()*90)/100;
final int width = (display.getWidth()*90)/100;
popUp = new PopupWindow(this);
layout = new LinearLayout(this);
tv = new TextView(this);
imageView = new ImageView(this);
imageView.setImageResource(R.drawable.ic_launcher);
params = new LayoutParams(width,height-50);
layout.setOrientation(LinearLayout.VERTICAL);
layout.addView(imageView, params);
Button button = new Button(this);
button.setText("Close");
params2 = new LayoutParams(100,50);
layout.addView(button,params2);
popUp.setContentView(layout);
button.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// TODO Auto-generated method stub
popUp.dismiss();
click = true;
}
});
Button ViewBmi = (Button) findViewById(R.id.button1);
ViewBmi.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (click) {
popUp.showAtLocation(layout, Gravity.CENTER, 10, 10);
popUp.update(10, 20, width,height);
click = false;
} else {
popUp.dismiss();
click = true;
}
}
});
}
Try This....
Button button = new Button(this);
button.setText("Close");
params2 = new LayoutParams(100,50);
--->params2.setMargins(100, 0, 0, 0);
layout.addView(button,params2);
I'd do it like this:
height = (int)(0.9*getWindow().getWindowManager().getDefaultDisplay().getHeight());
params.height = height;
Try:
params = new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT);
...
layout.addView(imageView, params);
This way the ImageView will be as wide, as possible.
If the underlying dialog is not wide enough, then you can set it's width also full screen:
WindowManager.LayoutParams params = getWindow().getAttributes();
params.height = LayoutParams.WRAP_CONTENT;
params.width = LayoutParams.MATCH_PARENT;
getWindow().setAttributes(params);
Or if you want it to be for example 90% of the screen, then:
// get the width of the whole screen
Display display = getWindow().getDefaultDisplay();
int fullScreenWidth = display.getWidth();
//then set 90% of it to the width of the Dialog:
int dialogWidth = (int) fullScreenWidth * 0.9);
WindowManager.LayoutParams params = getWindow().getAttributes();
params.height = LayoutParams.WRAP_CONTENT;
params.width = dialogWidth;
getWindow().setAttributes(params);