I want to highlight all the accessability clickable objects on screen. For this i create an app with an always on top layout.
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics displaymetrics = new DisplayMetrics();
int screenWidth = displaymetrics.widthPixels;
int screenHeight = displaymetrics.heightPixels;
params = new WindowManager.LayoutParams(
720, 1280,
0, 0,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
| WindowManager.LayoutParams.FLAG_FULLSCREEN,
PixelFormat.TRANSLUCENT);
mWindowManager.addView(testDrawView, params);
I also create an accessability service, in order to take all the accessability clickable elements box parameters. It works and the output is printed.
enter image description here
But the problem is that it doesnt update. When i do something on screen (all touches go through), i need the highlights of old elements to be deleted, and the higlight of new elements to be displayed. But changes do not update dynamycally, I need to open my app to force drawer to run.
I tried
class BrRec extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
mHeadLayer.rects.clear();
mHeadLayer.rects = (ArrayList<Rect>) intent.getSerializableExtra("rects");
for (int i = 0; i < mHeadLayer.rects.size(); ++i)
{
mHeadLayer.invalidate(mHeadLayer.rects.get(i));
}
mHeadLayer.invalidate();}}
But it doesnt work.
Is there a way to dynamically highlight screen objects? I want to redraw my always on top view, even when it is not active.
Maybe activate it somehow programatically?
Related
I have a custom view that adds a variable filter (light effects, etc) over the entire screen. This runs as a service when the main activity is closed, so the user can change apps etc with the filters running.
The code is effectively:
EffectsView view = new EffectsView();
WindowManager windowManager = (WindowManager) service.getSystemService(Context.WINDOW_SERVICE);
windowManager.addView(view, new Params());
private class Params extends WindowManager.LayoutParams
{
public Params()
{
super();
this.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
this.width = WindowManager.LayoutParams.MATCH_PARENT;
this.height = WindowManager.LayoutParams.MATCH_PARENT;
this.flags = 280;
this.format = PixelFormat.TRANSPARENT;
}
}
I'm currently using the flags = 280 parameter as it covers the notification bar, but it doesn't cover the soft nav buttons. This is most noticeable in the App Switcher.
I have tried the using the flag WindowManager.LayoutParams.FLAG_FULLSCREEN, but that doesn't cover the nav buttons or the notification bar.
Is there a way to get the view to cover the nav bar area?
Note: my supported SDK versions are 17+
I'd like to draw a (mouse pointer) icon on screen over the other applications from a service. I have implemented the functionality and I can draw over the screen, apart from the navigation bar. I've researched several other questions here and tried TYPE_SYSTEM_OVERLAY, TYPE_TOAST, TYPE_SYSTEM_ERROR and some other window types without success.
I'm not trying to capture focus, just drawing a mouse pointer on the screen for a second or two. When I try to draw over navigation bar, it just goes under (actually, the RelativeLayout ends on the border with navigation bar - even when I specify manual dimension for height). The screenshot below shows the hand pointer in the lower right part of the screen. That's as low as I can position it. Note that I'm not trying to hide the navigation bar in my application - trying to draw over other apps.
I even tried setting the xpos and ypos offset settings in WindowManager.LayoutParams instance, but that just offsets the layout and still goes below the navigation bar).
The layout params I'm using to show this window:
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
PixelFormat.TRANSPARENT);
I am then adding the RelativeLayout with those parameters to the WindowManager: windowManager.addView(relativeLayout, params);
After a lot of fiddling, I've managed to get the right flags to make it work. It almost works (for most apps). The code to achieve follows (an example on button click handler):
#Override
public void onClick(View view) {
if (_windowManager == null) {
_windowManager = (WindowManager) MainActivity.this.getSystemService(Context.WINDOW_SERVICE);
}
WindowManager.LayoutParams params;
// create the view on the first try
if (_overlayView == null) {
ImageView hand;
_overlayView = new FrameLayout(MainActivity.this);
hand = new ImageView(MainActivity.this);
hand.setImageResource(R.drawable.icon_hand_pointer);
int w = hand.getDrawable().getIntrinsicWidth();
int h = hand.getDrawable().getIntrinsicHeight();
_overlayView.addView(hand);
params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_FULLSCREEN |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS |
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
params.width = w;
params.height = h;
params.gravity = Gravity.LEFT | Gravity.TOP;
params.x = _xOffset;
params.y = _yOffset;
_windowManager.addView(_overlayView, params);
} else {
// move the view
params = (WindowManager.LayoutParams) _overlayView.getLayoutParams();
params.x = _xOffset;
params.y = _yOffset;
_windowManager.removeView(_overlayView);
_overlayView.setLayoutParams(params);
_windowManager.addView(_overlayView, params);
}
_xOffset += 40;
_yOffset += 100;
}
Here is a screenshot of this code working in an app (you can see the hand overlay; this is on Nexus 5 with Android 6.0.1:
The navigation bar at the bottom is something that cannot be drawn over because the items drawn above might impede access to the home button, back button, etc. But you can make your activity full-screen, meaning that it will hide the navigation buttons until you swipe up from the bottom, so that you can be free to draw anywhere on the screen
EDIT: I found some similar questions and this one has an answer : Draw bitmaps on top of the Navigation bar in Android
The answer was to add a y offset that's the size of the navigation bar.
I have created a service which will overlay an image on top of the whole screen.
This part is the code which will overlay an image on top of the whole screen:
#Override public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
img = new ImageView(this);
img.setImageResource(R.drawable.image); // Image is .png format
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.CENTER | Gravity.CENTER;
params.x = 0;
params.y = 0;
windowManager.addView(img, params);
}
However, any space which the image covers in untouchable. I want the image to be just overlaid, without affecting any other components on the screen, similar to what this does:
How can I make the area beneath the image touchable (touch-through)?
Edit
It seems that the transparent space of the image fills a square, and covers the screen (FYI).
So my ultimate goal is, to make the image touch-through.
I have tried the popupWindow class, recommended by a few SO users, but its purpose does not fulfill my needs and does not work.
I found that WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY solves the issue.
Try
img.setClickable(false);
http://developer.android.com/reference/android/view/View.html#setClickable(boolean)
Try setting the param flags to:
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
I've tried this with success before. The last two will help send touch events to the views behind it.
I use the following code to create on the flight a window used as preview when a picture is taken:
void CreatePreviewDialog()
{
dummy_frame_layout = new DummyFrameLayout(context);
wm_params = new WindowManager.LayoutParams(
240, 320, 0, 0,
WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON|
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD|
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED|
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON|
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
PixelFormat.TRANSLUCENT);
wm_params.gravity = Gravity.CENTER;
wm_params.setTitle("Preview");
window_manager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
window_manager.addView(dummy_frame_layout, wm_params);
}
My app runs in background and it is waked-up by an alarm. It turns-on the display as you can see. As soon as the picture is taken, the window is destroyed using the following method:
void DestroyPreviewDialog()
{
((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).removeView(dummy_frame_layout);
dummy_frame_layout = null;
}
The problem is that the screen remains on. I would like to turn-off the screen when the preview window is closed. How does DestroyPreviewDialog() should be modified in such a way to turn-off the display? (of course the display should be turned off only if it was found turned off when CreatePreviewDialog() was called, but this is simple. For now I need a way to turn off the display)
EDIT
I've modified DestroyPreviewWindow() as follows:
private void DestroyPreviewDialog()
{
wm_params.screenBrightness = 0.0f;
window_manager.updateViewLayout(dummy_frame_layout, wm_params);
((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).removeView(dummy_frame_layout);
dummy_frame_layout = null;
}
but the results does not change. Screen remains on and bright!
I recently saw an image of an app that was capable of displaying a view above the status bar and was also able to cover it with a view.
I know you can get a view right below the status bar from a view with align parent top. But how would you get a view on top of the status bar??
Example
Disable the System Status Bar - Without Root
After two full days of searching through SO posts and reading the Android docs over and over.. Here is the solution that I came up with. (tested)
mView= new TextView(this);
mView.setText(".........................................................................");
mLP = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
100,
// Allows the view to be on top of the StatusBar
WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
// Keeps the button presses from going to the background window
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
// Enables the notification to recieve touch events
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |
// Draws over status bar
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
PixelFormat.TRANSLUCENT);
mLP.gravity = Gravity.TOP|Gravity.CENTER;
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
mWindowManager.addView(mView, mLP);
Dont forget the permissions:
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
Note:
Tested upto kitkat.
The answer by #Sadeshkumar is incorrect for ICS and above (perhaps GB as well).
A view created with TYPE_SYSTEM_ALERT and FLAG_LAYOUT_IN_SCREEN is covered by the StatusBar.
To get an overlay on top of the StatusBar, you need to use TYPE_SYSTEM_OVERLAY instead of TYPE_SYSTEM_ALERT.
The problem being then, how to get clicks/touches?
A view created with TYPE_SYSTEM_ERROR and FLAG_LAYOUT_IN_SCREEN is covered by the StatusBar.
int statusBarHeight = (int) Math.ceil(25 * getResources().getDisplayMetrics().density);
View statusBarView = new View(MyActivity.this);
statusBarView.setBackgroundColor(Color.GREEN);
WindowManager.LayoutParams params = null;
params = new WindowManager.LayoutParams(WindowManager.LayoutParams.FILL_PARENT,statusBarHeight,WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL |WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT);
params.gravity = Gravity.RIGHT | Gravity.TOP;
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(statusBarView, params);