I am trying to add a view(ImageButton for example) to Window using WindowManager.addView(button),
What are the layout params so that the button can be seen on "lock screen".
Thanks in advance.
You can try adding type as WindowManager.LayoutParams.TYPE_SYSTEM_ERROR in the WindowManager.LayoutParams constructor which is illustrated below :
WindowManager.LayoutParams params=new WindowManager.LayoutParams();
params.type=WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
The aforementioned lines will make the view to appear on lock screen where you can capture touch events, click events and many others; However, you can use the below-mentioned flag for the non-touchable view.
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY
Note: As per Android Developers The above-mentioned both flags are deprecated in API Level 26 and so you can use the flag TYPE_APPLICATION_OVERLAY as a substitute.
You have to make an activity with transparent background with view on the top which you want to show on the lockscreen. Now call that activity when your phone wakes up.
Note : You have to make an service which will start your activity. You have to register a broadcast receiver to that service.
public class CrackService extends Service
{
CrackView renderView;
LayoutParams params;
WindowManager wm;
#Override
public void onCreate()
{
params = new WindowManager.LayoutParams( WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(renderView, params);
}
#Override
public IBinder onBind(Intent intent)
{
// TODO Auto-generated method stub
return null;
}
}
Related
I'm new to the accessibility stuff on Android. While going through the classes and documentation I came across TYPE_ACCESSIBILITY_OVERLAY inside the WindowManager class.
The documentation says (only the relevant text)
For example, if there is a full screen accessibility overlay that is
touchable, the windows below it will be introspectable by an
accessibility service even though they are covered by a touchable
window.
So I set out to achieve just that, a full screen accessibility overlay and try to introspect the windows below it
Extended AccessibilityService and added my full screen overlay when onServiceConnected is called (the inspiration for adding overlay came from here)
#Override
protected void onServiceConnected() {
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
FrameLayout mLayout = new FrameLayout(this);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
lp.format = PixelFormat.TRANSLUCENT;
lp.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
lp.width = WindowManager.LayoutParams.MATCH_PARENT;
lp.height = WindowManager.LayoutParams.MATCH_PARENT;
lp.gravity = Gravity.TOP;
wm.addView(mLayout, lp);
mLayout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
// Here I'm getting the touch events on the overlay I added
return false;
}
});
}
Now, the question is, how do I introspect or find the windows below this overlay? Even in the onAccessibilityEvent callback I get just this overlay window. getWindows() always has a size of 1. Doesn't it refute the assertion made above for TYPE_ACCESSIBILITY_OVERLAY?
Relevant info: To receive the touch events on the overlay I have disabled touchExplorationMode in the service settings
android:canRequestTouchExplorationMode="false"
What you seem to be missing is flagRetrieveInteractiveWindows on your configuration. These properties and window layout paremeters configuration should work, without requiring for you to disable canRequestTouchExplorationMode in order to get the events and having getWindows return the AccessibilityWindowInfo instances underneath yours:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:packageNames="test.demo.com.tests"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFlags="flagRetrieveInteractiveWindows|flagReportViewIds|flagIncludeNotImportantViews"
android:accessibilityFeedbackType="feedbackAllMask"
android:notificationTimeout="100"
android:canRetrieveWindowContent="true"
/>
And on service connected:
#Override
protected void onServiceConnected() {
WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
FrameLayout layout = new FrameLayout(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE|
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS|
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP;
windowManager.addView(layout, params);
layout.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
//You can either get the information here or on onAccessibilityEvent
return false;
}
});
}
EDIT:
Added FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS to accomplish full screen and removed canRequestTouchExplorationMode since the flag associated to this property should not be included and, therefore, of no use.
I want to detect pressing of a back button in service. I've just tried this code but it didn't show me any log. Can somebody explain me why? And what should I do to make it work?
The whole idea of doing this was was taken from this tutorial http://www.kpbird.com/2013/03/android-detect-global-touch-event.html
public class MyService extends Service implements View.OnKeyListener{
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
LinearLayout touchLayout = new LinearLayout(this);
// set layout width 30 px and height is equal to full screen
LayoutParams lp = new LayoutParams(30, LayoutParams.MATCH_PARENT);
touchLayout.setLayoutParams(lp);
touchLayout.setBackgroundColor(Color.RED);
touchLayout.setOnKeyListener(this);
WindowManager mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
// set layout parameter of window manager
WindowManager.LayoutParams mParams = new WindowManager.LayoutParams(
30, // width of layout 30 px
WindowManager.LayoutParams.MATCH_PARENT, // height is equal to full screen
WindowManager.LayoutParams.TYPE_PHONE, // Type Phone, 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;
mWindowManager.addView(touchLayout, mParams);
}
#Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK){
Log.v("Point","KeyCode_Back");
return false;
}
return false;
}
}
Your Service is not a View, implementing a View.OnKeyListener does not deliver your desired functionality.
A Service is intended to be an "Activity without UI" which runs in the background of your application. You can use Binders/Broadcasts to communicate with your service but UI interaction is best left to Activity/Fragments.
Annex:
I guess you are trying to build a overlay like in the link you posted in the comment. This Tutorial is from 2013 so things have changed.
In general the Android system discourages App beheaviour like the below described method. Coding like this, goes into the category Lockscreen/Kiosk-App behaviour which is considered as malware.
If you want to accomplish a little side menu inside your app you can do this perfectly fine without using such a service. Outside your App you still have the options of using widgets, which are more user friendly than hardcoding something on the screen.
I'm trying to make a custom navigation button and have disabled the default navigation buttons provided by android by rooting my device. I want my custom navigation buttons to disappear after some interval of time (say 5 seconds). I have managed to do so. I want to make something such that whenever I touch anywhere on the screen, I can detect the touch event and show my navigation bar. Whether I'm on homescreen or any application, I can receive touch event. Is there a way to do so or do I need to go android source code?
Thank you
OnCreate of your Service: used WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH flag.
#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.
see this Creating a system overlay window (always on top)
I need to show a system overlay window on top of any running apps. It works fine, but only when my app's activity is in foreground. Here is the code I use:
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE |
WindowManager.LayoutParams.FLAG_DIM_BEHIND |
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.CENTER | Gravity.TOP;
params.dimAmount = 0.3f;
wm = (WindowManager) ctx.getSystemService(Context.WINDOW_SERVICE);
mainAlertView = View.inflate(ctx, R.layout.system_alert_view, null);
wm.addView(mainAlertView, params);
The view added to WindowManager contains empty LinearLayout to which I add child views at runtime:
mainAlertLayout.addView(childView);
Manifest xml has SYSTEM_ALERT_WINDOW permission defined:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
It all works magnificently while my activity is running in foreground. As soon as I switch to any other app or home screen no overlay is shown. I debugged the code, and it indeed is running wm.addView(), and its not throwing any exceptions. I also played around with LayoutParams flags (removed KEEP_SCREEN_ON and related etc), but nothing made any difference.
Android 4.4.2 fwiw
You need to create a service to keep the system overlay( alert) to show even when your application closed.
Create a simple service , I will call as FloatingService , which will show the overlay(alert) when onStartCommand is called . Return START_STICKY to keep the service run in background.
public class FloatingService extends Service {
private WindowManager windowManager;
private View floatingView;
WindowManager.LayoutParams params;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flag, int startId){
// show the alert her
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
// use your custom view here
floatingView = View.inflate(getBaseContext(),R.layout.floating_layout,null); //floatingView.setOnTouchListener(mOnTouchListener);
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.CENTER | Gravity.CENTER;
// add the view to window manger
windowManager.addView(floatingView, params);
return START_STICKY;
}
}
Add an listener to the view so that you can close the overlay(alert) when required
floatingView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
windowManager.removeView(floatingView);
floatingView = null;
}
});
Finally , register the service in manifest
<service android:name="com.example.app.services.FloatingService" />
And System Alert permission
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
The problem was that I was running addView() call in main view's post() method:
mainView.post(new Runnable() {
public void run() {
wm.add(mainView);
}
);
Instead if I just run it in main thread it works fine. I use de.greenrobot.eventbus and its very simple to post Runnable to event bus and ensure it executes in main thread:
public void onEventMainThread(UIRunnableEvent event) {
event.r.run();
}
public static class UIRunnableEvent {
protected Runnable r;
protected UIRunnableEvent(Runnable r) {
this.r = r;
}
}
I have implemented some features by integrating accessibility service for my application.
I currently have a 'system overlay' ImageView that can detect TouchEvent's. however i have seen it done that immersive mode, hiding the statusbar or navbar is possible without root.
i need to beable to access the view of my touch detection window in order to process any accessibility
My Accessibility service contains:
...
#Override
public void onServiceConnected() {
serviceInstance = this;
}
...
my touch detector:
...
WindowManager wm;
private MyAccessibilityService myAccessibilityService;
private ImageView mTouchDetector;
#Override
public void onCreate() {
super.onCreate();
myAccessibilityService = MyAccessibilityService.getSharedInstance();
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
100,
100,
0, 0,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, debugMode());
params.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mTouchDetector, params);
}
...
I have partially solved this problem, however having some trouble with the back button, check here to see if it gets resolved.
create the service as normal but add these flags to the overlay:
to the window manager:
TYPE_PRIORITY_PHONE, FLAG_FULLSCREEN |
FLAG_NOT_TOUCH_MODAL
to the view:
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
FloatingView.setSystemUiVisibility(uiOptions);
Android floating window with hidden statusbar Accessibility problems