Prevent application with SYSTEM_ALERT_WINDOW from obscuring my application - android

Is there any way to assure that my application's window is not obscured by any other application's view using with SYSTEM_ALERT_WINDOW permission?
If not, then is there any better way to assure that my app is not obscured by such window apart from obtaining the same permission and refreshing/showing/whatever my own view (of course shown in alert window) every 100ms or so to keep it visible?
Eventual flickering, in case my application is obscured, is actually a good thing and an indicator to the user that something is wrong.
EDIT: It seems that there is no way to do it except from going through KNOX on Samsung or some other proprietary solution for Trusted UI. Accepted answer is enough for my purpose, but it is not an answer for the question asked.

Even if it's not exactly what you're asking, the closest replacement I know of is:
Either setting android:filterTouchesWhenObscured="true" in your layout (touch events will be filtered and not reach your View if they are going through an overlay, regardless is transparent or opaque). See View#setFilterTouchesWhenObscured(boolean),
Or overriding View#onFilterTouchEventForSecurity(android.view.MotionEvent) and checking for FLAG_WINDOW_IS_OBSCURED. See View#onFilterTouchEventForSecurity(android.view.MotionEvent).
Later can be implemented like so:
override fun onFilterTouchEventForSecurity(event: MotionEvent): Boolean {
if ((event.flags and MotionEvent.FLAG_WINDOW_IS_OBSCURED) == MotionEvent.FLAG_WINDOW_IS_OBSCURED) {
Toast.makeText(context, "Screen overlay detected!", Toast.LENGTH_LONG).show()
return false // touch event is cancelled
}
return super.onFilterTouchEventForSecurity(event)
}
See also the Security section of View class documentation.
Notice that this functionality is available from API 9+. A workaround for older APIs can be found in this SO Question: Analogue of android:filterTouchesWhenObscured for API level below 9.

Related

Android fingerprint auth through alertdialog?

I want to have the user use fingerprint authentication to allow them to perform an action within my app. I have already performed the necessary check, does the hardware exist, is a fingerprint registered etc when they say they would like to use fingerprint auth.
An alertdialog currently opens when it is time for the user to authenticate with their fingerprint. I'd like to know if it is actually possible to catch the fingerprint through an alertdialog as and alertdialog afaik only has positive and negative button input options.
If it is not possible to do this through an alertdialog, a point in the right direction would be much appreciated.
EDIT: Just to be clear, I don't mean using the screen as a fingerprint sensor.
You can use this FingerprintDialog library. Then it goes simply like this :
FingerprintDialog.initialize(this)
.title(R.string.title)
.message(R.string.message)
.callback(new FingerprintCallback({
#Override
public void onAuthenticationSuccess() {
// Fingerprint recognized
}
#Override
public void onAuthenticationCancel() {
// User pressed cancel button
}
}))
.show();
Otherwise, you just have to create a custom xml layout, get the view using a LayoutInflater and call setView(view) on the dialog. Google it.
This currently isn't possible. Or if it is, I really doubt it. Most touch screen phones use a capacitive touch. Which means, since our fingers conduct electricity, we disturb the electric fields infront of the phone's screen. While it does support multitouch, I really doubt it's so precise that it detects the ridges on our fingers.
You would need more of a heat sensitive touch screen. Which I don't think they use in most new generation touch screens.
So you could use this API https://developer.android.com/reference/android/hardware/fingerprint/FingerprintManager.html but only in device that contains fingerprint scan and definitely not through the screen of you device.

How to listen to taps and get views using Accessibility in Android?

I want to implement an Accessibility service in my Android app which can do the following things:
=>Get the onscreen taps/clicks across any apps.
=>Get the view which was tapped/clicked.
Initially I thought it would not be possible to do so because of security reasons but while doing some research I came across an app (Native clipboard) which could do following things:
=>Detect taps on EditTexts from any app
=>Add value (string) to those EditTexts.
I also saw Google's talkback which speaks whatever you tap on. For it to speak, it needs to access the view (to get the text) across apps.
These apps obviously makes use of 'Accessibility services' to do so, but I would like to know how can I implement that?
I mostly find tutorials or stuffs for things I need to achieve but I am struggling finding some for implementing Accessibility service for my app. I did visit the Android official documentation which is too technical for a newbie like me. (I initially prefer to learn from Youtube, SO and tutorial websites). It will also be great if you can pin point me to some other tutorials which covers these things.
Accessibility services are pretty poorly documented, but I have created some accessibility service boilerplate code, that sets up a starter project and logs the base callbacks. Here is a bit of code that I think you care about given your specific questions. The scaffolding, project set up and such I leave for the repo.
Below is the onAccessibilityEvent callback. This is where you will listen for different types of a events, and the most convenient place to grab onto screen content for most scenarios. Though, as an accessibility service you also don't have to wait for events. You could just as easily spawn an AsynTask and grab on to it on an interval of some kind.
public void onAccessibilityEvent(AccessibilityEvent event) {
CLog.d(event.toString());
switch (event.getEventType()) {
//On Gesture events print out the entire view heirarchy!
case AccessibilityEvent.TYPE_GESTURE_DETECTION_START:
CLog.d(A11yNodeInfo.wrap(getRootInActiveWindow()).toViewHeirarchy());
case AccessibilityEvent.TYPE_VIEW_CLICKED:
CLog.d(event.getSource().toString());
default: {
//The event has different types, for you, you want to look for "action clicked"
if (event.getSource() != null) {
CLog.d(A11yNodeInfo.wrap(event.getSource()).toViewHeirarchy());
}
}
}
}
I will point out one bit of configuration for this, because it is super important. Accessibility services are best configured through an XML file connected to your service through the Manifest file. The contents of this file are:
<?xml version="1.0" encoding="utf-8"?>
<accessibility-service
xmlns:android="http://schemas.android.com/apk/res/android"
android:description="#string/accessibility_service_description"
android:accessibilityEventTypes="typeAllMask"
android:accessibilityFlags="flagReportViewIds"
android:canRetrieveWindowContent="true"
android:canRequestTouchExplorationMode="true"
android:accessibilityFeedbackType="feedbackSpoken"
android:notificationTimeout="100"
android:settingsActivity="com.moba11y.basicaccessibilityservice.SettingsActivity"
/>
For you the important bits are canRetrieveWindowContent="true" and accessibilityEventTypes="typeAllMask". A design bit I like, is ensuring that your grabbing onto the minimal set of event types you want. Different Accessibility Events report broadly different results. For example, many events return "null" from getSource(). This forces you to add a lot of filters for this, or risk null pointer exceptions. It's quite annoying.
The last bit you need is Accessibility Actions. This is what allows you to simulate clicks, long clicks AND add text to an editable text view. Below is code that allows you to do this.
public void onAccessibilityEvent(AccessibilityEvent event) {
AccessibilityNodeInfo source = event.getSource();
if (source != null & event.getClassName().equals("android.widget.EditText")) {
Bundle arguments = new Bundle();
arguments.putCharSequence(
AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE,"some value");
source.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);
}
}
https://github.com/chriscm2006/Android-Accessibility-Service-Boilerplate

Button unpresses itself (possibly device specific)

I'm trying to troubleshoot a tricky, difficult to reproduce (therefore possibly hardware related) problem for the open source Panic Button application I'm working on for Amnesty. There's an issue on github about it.
The issue is with a LinearLayout View with Buttons. When displayed in this fragment, when I try to hold a button, it just unpresses itself after one second exactly. When logging the onClick event, it triggers itself automatically even though I haven't released my finger from the screen.
This happens on the Cherry Gem phone, and I wasn't able to reproduce the problem on other phones.
I've been removing a lot of code and adding lots of logging statements to try and isolate the bug when I discovered the strangest thing, which led me to post this on Stack Overflow since it's strange enough that maybe someone will recognise the pattern:
When I drag my finger on the screen, then the bug goes away! More precisely, after confirming on the screen that the button unpresses itself a few times, if I hold and drag my finger around, then release it, after that I can hold buttons pressed without them unpressing themselves. Wat?
Please note that I'm not asking to solve the problem of trying to detect a long press (which this leads to of course), but trying to understand this problem of unwanted unpressing before I move on to implement a workaround. Therefore I'd also would prefer not to move the events to onTouch listeners, because I'm worried it would not address the root cause of the problem and I'd like to understand why this is happening first.
I'm not a 100% sure if there could be an unwanted interaction with the rest of the code and will also try to create a minimalistic project from scratch with only that code, if no-one recognises the pattern here.
I can also post a small video of the problem if that helps. I'm also happy to post code excerpts or logcat results.
Thanks for your time!
Jun
Update
I've looked at the adb shell getevent log which confirms that after .9 seconds there is an EV_KEY BTN_TOUCH UP
event. Does this confirm that from the OS's standpoint, it's receiving an event from the hardware about a button up? I guess this might be also triggered by software.
This led me to look into software that is installed on the phone and could interfere with the input devices. I've deactivated the Google voice typing, and then holding buttons worked again. Reactivating Google voice typing didn't make the bug reappear. Rebooting the phone then makes the bug reappear.
I tried to look at whether only some applications were affected. The pre-installed calculator was also affected. When using the default virtual keyboard the bug didn't happen. But then when returning to my app the bug had gone away again. Rebooted again. Calculator still affected. Go back to using the virtual keyboard in the browser. Now the bug stays... Wat?
After a while, I removed the Google voice typing input device again and the bug disappeared once more.
I have tracked a forum where there seems to be a rom for this phone, I'm trying to find out whether it's more recent than the version I have, or if anyone else with this phone experienced that problem as well.
(I also updated the relevant github issue)
Update 2
I noticed the following in the logcat:
04-01 12:05:30.484: V/PhoneWindow(2749): DecorView setVisiblity: visibility = 0
04-01 12:05:30.525: V/InputMethodManager(2749): onWindowFocus: null softInputMode=288 first=true flags=#1810100
04-01 12:05:30.528: V/InputMethodManager(2749): START INPUT: com.android.internal.policy.impl.PhoneWindow$DecorView{41aa5ef8 V.E..... R.....ID 0,0-480,800} ic=null tba=android.view.inputmethod.EditorInfo#41a3fef8 controlFlags=#104
04-01 12:05:30.530: V/InputMethodManager(2749): Starting input: Bind result=InputBindResult{com.android.internal.view.IInputMethodSession$Stub$Proxy#41a48da8 com.android.inputmethod.latin/.LatinIME #45}
04-01 12:05:30.608: I/InputMethodManager(2749): handleMessage: MSG_SET_ACTIVE true, was false
Could this be part of the problem?
For odd problems such as this, I think it's useful to override the onTouchEvent listener, and observe which MotionEvent is triggered (like ACTION_MOVE, ACTION_UP/DOWN). The root problem may be the touch screen driver of the device. So it may be good to test that driver with onTouchEvent.
There is, I think, a good webpage # Touch Device Configuration. Search text for "Driver reports signal strength as pressure". I think this is interesting and perhaps you could simply change the values for touch.pressure.calibration or/and scale for troubleshooting. This file has extension of idc, should reside on system subdirectory.
I want to provide sample code to override mouse/swiping events:
#Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction() & MotionEvent.ACTION_MASK) {
// Make sure ACTION_DOWN is dispatched to children view
case MotionEvent.ACTION_DOWN:
onTouchEvent(ev);
// Allow the children view to process this action
return false; // skip calling onInterceptTouchEvent
case MotionEvent.ACTION_MOVE:
onTouchEvent(ev);
return false;
default:
break;
}
return super.onInterceptTouchEvent(ev);
}
#Override
public boolean onTouchEvent (MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mDownX = (int)event.getX();
mDownY = (int)event.getY();
break;
case MotionEvent.ACTION_MOVE:
...
Notes:
Method onInterceptTouchEvent occurs before onTouchEvent.
This method intercepts all touch screen motion events. This allows you to watch events as they are dispatched to your children.

Android Wear BoxInsetLayout isRound always returns false

I'm building an Android Wear app and trying to implement BoxInsetLayout for round screens. In my code, I want to detect if the device is round or not, so I'm using BoxInsetLayout's isRound() function, but it always returns false, even on the Moto 360.
Anyone know if there's a way to programmatically tell if the device is round?
The problem may be caused by calling isRound() at the wrong time. The round-ness is determined by the WindowInsets being delivered to the BoxInsetLayout. If you call isRound() very early before the insets have been delivered, you will get the wrong answer.
So if you have a "box" object which is the BoxInsetLayout, you would do this:
box.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
#Override
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
// Need to also call the original insets since we have overridden the original
// https://developer.android.com/reference/android/view/View.OnApplyWindowInsetsListener.html
box.onApplyWindowInsets(windowInsets);
// You can make calls to detect isRound() here!
// Return the insets so the BoxInsetLayout still works properly
return windowInsets;
}
});
Can you please send us the code related to the BoxInsetLayout that you are using?
According to Wayne answer on G+ it is a bug, for now we know what causes it, how to avoid it but only if user is aware of that, but fix for it is not released (yet).
https://plus.google.com/108847189842978537754/posts/5YiYb14i7ss
Quoting as post might be deleted/changed:
The problem is triggered by the watch switching languages when pairing with a phone after a factory reset. You can avoid the issue by
selecting the same language on the wearable as you are using on the
phone, so that no change occurs afterwards when the devices are
paired.
Instructions to fix the problem:
Factory reset the Moto 360.
When the wearable restarts, it will ask what language you would like to use. Select the same language that you are using on the phone
(do not select the default of English)
On the phone, start the Android Wear companion app, and select from the overflow menu the option "Pair with a new wearable".
Pair the phone with the Moto 360.
EDIT:
Using setOnApplyWindowInsetsListener (suggested by Wayne) I created small class that simplify using it a bit. https://github.com/tajchert/ShapeWear
Just copy ShapeWear.java class, and subscribe to screen shape detection event setOnShapeChangeListener() or call method ShapeWear.isRound() (can throw error is shape is not yet determined) or ShapeWear. getShape() - which can result in ShapeWear.SHAPE_UNSURE in same situation.

Lock The Android device screen and prevent the user to unlock it

I am working in Android App that should prevent the user to use the mobile in some-cases .
So I tried to lock the screen
I used the PowerManger goToSleeo() Method
but it needs DEVICE_POWER permission. which is allowed only for the System apps, but my app is not a system app
what should I do ?
here is my code
PowerManager manager = (PowerManager) getSystemService(Context.POWER_SERVICE);
manager.goToSleep(600000);
Counterquestion: What purpose would it serve if normal apps could lock your screen? In my eyes, that's malware. You need the permission and nothing will ever change that. The only solution is to remove this "functionality".
Edit: Some more information by the way: Android What permissions required to call PowerManager.goToSleep(n) put device in sleep mode?
This sort of thing is difficult to do in Android for reason. You are trying to block access to the main OS, which is a bad thing. As other people have mentioned this could be used for malicious purposes (it is not a stretch to think someone could create a ransom-ware app that blocks your device, until you pay something to release it).
So bottom line - you CANNOT do what you are asking (and for good reasons). Especially on a non-rooted phone. One a device is rooted, you CAN do anything (including blocking access to the system buttons).
For more details about this, look into 'Kiosk' mode, or blocking system access (there are many SO questions about this).
You don't want to lock the device, that's deliberately designed against. You can, however, disable touch input by overriding onTouchEvent.
You then need to create a view, like so:
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<your code here>
<Disabletouch
android:id="#+id/black_hole"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</FrameLayout>
And define it like so:
public class DisableTouch extends View {
private boolean touch_disabled=true;
#Override
public boolean onTouchEvent(MotionEvent e) {
return touch_disabled;
}
public disable_touch(boolean b) {
touch_disabled=b;
}
}
Call it in the activity:
(DisableTouch) black_hole = findViewById(R.id.black_hole);
black_hole.disable_touch(true);
And reverse:
black_hole.disable_touch(false);

Categories

Resources