I have a system app (signed with platform keys), and this app is injecting events. It is using uinput and tries to use /dev/input/eventN (where N is a number) as well.
If I run the code as root (i.e. with su), the code can obviously open /dev/input/eventN and can inject events in there. If the code is run from the system app, I get permission denied when opening /dev/input/eventN with open("/dev/input/event1", O_RDWR). Uinput works fine, however, even in system app.
The permissions requested by the system app are:
<uses-permission android:name="android.permission.READ_FRAME_BUFFER"
tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.INJECT_EVENTS"
tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.BIND_INPUT_METHOD"
tools:ignore="ProtectedPermissions"/>
For what it's worth, this system app also reads screen, and is able to do so. So it is very strange it is not able to open with r/w /dev/input/eventN.
You might wonder what's wrong with uinput if that works. The problem with uinput is that I have problems injecting touch events. Specifically, I can not "click" (tap). I can drag, swipe, inject keyboard events, but clicking (tapping) just does not work. It seems as if it is stuck with long press. It does not register the final event, where ABS_MT_TRACKING_ID is set to 0xffffffff.
The code I'm using for "click" (tap) is:
// pointer down
send_event(EV_ABS, ABS_MT_SLOT, 0);
send_event(EV_ABS, ABS_MT_TRACKING_ID, m_tracking_id++ % 65535);
send_event(EV_ABS, ABS_MT_TOOL_TYPE, MT_TOOL_PEN);
// pointer coordinates
send_event(EV_ABS, ABS_MT_POSITION_X, x);
send_event(EV_ABS, ABS_MT_POSITION_Y, y);
send_event(EV_ABS, ABS_MT_TOUCH_MAJOR, m_tracking_id % 2 ? 0x3c : 0x30);
send_event(EV_ABS, ABS_MT_PRESSURE, m_tracking_id % 2 ? 20 : 25);
send_event(EV_SYN, SYN_REPORT);
// pointer up
send_event(EV_ABS, ABS_MT_TRACKING_ID, -1);
send_event(EV_SYN, SYN_REPORT);
Related
I'm using Qt (6.4.1) for android. I used to ask "ACCESS_FINE_LOCATION" permission to get GPS position using code like:
auto permissionGPS = QtAndroidPrivate::requestPermission("android.permission.ACCESS_FINE_LOCATION").result();
if(permissionGPS == QtAndroidPrivate::Authorized){
source = QGeoPositionInfoSource::createDefaultSource(0);
if (source) {
auto last = source->lastKnownPosition(false);
if(last.isValid()){
receivePosition(last);
}else{
connect(source, &QGeoPositionInfoSource::positionUpdated, this, &Locator::receivePosition);
source->startUpdates();
}
}
}else{
emit GPSRefusal(false);
}
Unfortunately if the user perfers to allow "ACCESS_COARSE_LOCATION", this code doesn't work anymore.
If I replace requested permission with "ACCESS_COARSE_LOCATION" (which is reasonable for my app), I get the following error:
W qt.positioning.android: : Position data not available due to missing permission 4
Does any one know how to get ACCESS_COARSE_LOCATION positioning working with Qt ?
For an Android 13 device you first have to request COARSE location permission.
And only after you obtained permission request gps FINE permission.
Two steps.
I was running into issues with the manual process behind requesting permissions (just kept falling into the 'denied' code), so I switched over to using Dexter to simplify. I implemented the following code in onCreate(), and I did a fresh install of the app:
Dexter.withActivity(this)
.withPermission(Manifest.permission.CAMERA)
.withListener(new PermissionListener() {
#Override public void onPermissionGranted(PermissionGrantedResponse response) {
Log.d(TAG, "GRANTED!");
initCamera();
}
#Override public void onPermissionDenied(PermissionDeniedResponse response) {
Log.d(TAG, "DENIED!");
}
#Override public void onPermissionRationaleShouldBeShown(PermissionRequest permission, PermissionToken token) {
Log.d(TAG, "PERMISSION RATIONAL SHOULD BE SHOWN!");
}
}).check();
It immediately falls into the "DENIED!" log, and it never even prompts me. I tried this particular code to attempt multiple permissions (which is ultimately what I need to do):
Dexter.withActivity(activity)
.withPermissions(Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE)
.withListener(new MultiplePermissionsListener() {
#Override
public void onPermissionsChecked(MultiplePermissionsReport report) {
Log.d(TAG, "Accepted: " + report.getGrantedPermissionResponses().size() + " | Denied: " + report.getDeniedPermissionResponses().get(0).getPermissionName());
}
#Override
public void onPermissionRationaleShouldBeShown(List<PermissionRequest> permissions, PermissionToken token) {
Log.d(TAG, "continuing permissions request..");
token.continuePermissionRequest();
}
})
.check();
It prompts for permissions to Record Audio, then it asks about Access to photos/media/files on the device (it never asks about Camera). Then once that's done, it prints the log: "Accepted 3 | Denied: android.permission.CAMERA". It denies it without even prompting me again.
My Manifest is set properly to have CAMERA in the proper place (outside of the 'application' tag). See below for reference:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.my.app">
<uses-feature
android:name="android.hardware.camera"
android:required="true" />
<permission
android:name="${applicationId}.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
etc..
Odd thing is that when I go into Settings > Applications > MyApp, the Camera option is not even displayed in there.
I don't think it's an issue with Dexter, since it's doing basically the same thing when I set it up manually (and I confirmed that it's definitely setup properly in that case after looking at a few top S.O. posts).
Any thoughts on what the issue could be here? FYI - I'm using a Galaxy S6, OS 6.0.2. The other users experiencing this seem to be other devices with 6.0+ OS. Thanks in advance!
EDIT:
Testing various devices, it works on some and does not work on some:
Moto X (OS 5.0) - Broken
Nexus 5 (OS 7.0) - Works
Samsung S6 (OS 6.0.1) - Broken
Broken Moto X (OS 6.0) - Works
Doesn't seem to be a solid pattern.. Definitely strange. I also started a brand new project and ran the same code - worked fine and allowed access to my camera. So it doesn't appear to be fully device-specific..
The issue with this turned out to be a third-party library, which had this line in their Manifest, overriding our own permission:
<uses-permission android:name="android.permission.CAMERA" tools:node="remove" />
The solution was either to manually import their project as a module (rather than use gradle), and then comment out that line, OR more simple - you can add "tools:node="replace"" to the end of the main project's CAMERA permission line, and it works fine after that; no need to import the project with the latter approach.
What you need is native runtime permissions not dexter, Beginning in Android 6.0 (API level 23), users grant permissions to apps while the app is running, not when they install the app. This approach streamlines the app install process, since the user does not need to grant permissions when they install or update the app. It also gives the user more control over the app's functionality; for example, a user could choose to give a camera app access to the camera but not to the device location. The user can revoke the permissions at any time, by going to the app's Settings screen.
// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.YOUR_PERMISSION);
then what you need is to request a certain permission if that check is false,
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.YOUR_PERMISSION},
MY_PERMISSION_CODE);
Bare in ind that you need to as well declare them also in the manifest, based on what you have shown still that was already done. For more information.
I've read a really lot of posts yet, but the problem still occurs...
My app needs calendar permission, and this wil work fine till Android 5.
In my trap.xml in the permissions ar set as followed:
<android xmlns:android="http://schemas.android.com/apk/res/android">
<manifest>
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="23"/>
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
</manifest>
</android>
When I try to set the permission like I found on Jira:
function calenderTask() {
if (Ti.Calendar.hasCalendarPermissions()) {
showCalendars(Ti.Calendar.selectableCalendars);
} else {
Ti.Calendar.requestCalendarPermissions(function(e) {
if (e.success) {
showCalendars(Ti.Calendar.selectableCalendars);
} else {
Ti.API.error(e.error);
alert('Access to calendar is not allowed');
}
});
}
}
function showCalendars(calendars) {
for (var i = 0; i < calendars.length; i++) {
Ti.API.info("Calender: "+calendars[i].name);
}
}
calenderTask();
only after a fresh install on the device (Samgung S7, Android 6) there is some action when I place an alert in the code.
The next run it looks like the code is ignored.
And... most important of all, there is no permissions set.
When I manually set the permission in the settings of my device, the app works fine.
Please is there somebody with a solution for me?
I'm also trying to find a better way of checking Calendar permissions on Android 6.
Meanwhile, I'm using this code to send the user right to the app settings on a dialog:
var dialog = Ti.UI.createAlertDialog();
dialog.message = 'Please check your calendar permissions';
dialog.cancel = 1;
dialog.buttonNames = ['Settings', 'Cancel'];
dialog.addEventListener('click', function(e){
var intentData = {action: "android.settings.APPLICATION_DETAILS_SETTINGS", data: "package:" + Ti.App.getId()};
var flags = [ Ti.Android.FLAG_ACTIVITY_NEW_TASK, Ti.Android.FLAG_ACTIVITY_NO_HISTORY, Ti.Android.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS];
if (e.index === 0){
win.openIntent(intentData, flags);
}
});
dialog.show();
I hope it helps a bit...
I found a solution/workaround for my problem that the calendar permission was not asked for.
In the settings section of the device I removed the permissions by hand by the specific app. Now I did a reset on all settings of the installed app's and then the question is asked on the device when I start the particular part of the app.
Thus just remove the permissions and delete the app from the device is not enough!
I've used the part of code that I listed before, that from Jira.
So, for the moment my problem is solved (I think) and the app is asking for the needed permissions after first install.
Carlos, thanks for your comment, and I hope you can do something with my investigations too.
I created a TYPE_SYSTEM_ALERT view, set the flags FLAG_NOT_TOUCH_MODAL and FLAG_WATCH_OUTSIDE_TOUCH, and added it with WindowManager.addView().
When I touch outside of the view onto my own activity, everything works and MotionEvent.getY() returns the correct value.
However, if I exit my activity and and touch onto another application, MotionEvent.getY() always returns 0.
I'm not sure if this only happens on 4.2 or not.
Any help would be appreciated!
It's unfortunate that this question has remained unanswered for 1.5 years, but I ran into the same thing you did and found out why!
After scouring the source code, I found the source of the issue:
https://github.com/android/platform_frameworks_base/blob/79e0206ef3203a1842949242e58fa8f3c25eb129/services/input/InputDispatcher.cpp#L1417
// Check whether windows listening for outside touches are owned by the same UID. If it is
// set the policy flag that we will not reveal coordinate information to this window.
if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
sp<InputWindowHandle> foregroundWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;
for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
sp<InputWindowHandle> inputWindowHandle = touchedWindow.windowHandle;
if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) {
mTempTouchState.addOrUpdateWindow(inputWindowHandle,
InputTarget::FLAG_ZERO_COORDS, BitSet32(0));
}
}
}
}
If the "outside touch" lands in a view that doesn't share its UID (read about it here) with the view that's listening for outside touches, the event dispatcher sets its coordinates to 0,0. This was definitely done for security purposes, but I'm not sure I see the full scope of the threat it's designed to mitigate. And this gentleman here (SO) reports that you can retrieve location data on 2.3.6, but it seems that at least 4.x won't reveal it to you (I tried 4.1.2, it didn't work).
I opened up a bug ticket about this if you'd like to follow it. At the very least, the documentation needs to include this information... I would also like to know if this security feature is really necessary.
Issue 72746: FLAG_WATCH_OUTSIDE_TOUCH doesn't return location for ACTION_OUTSIDE events on 4.2+
Android contains a permission called 'ACCESS_LOCATION_EXTRA_COMMANDS'. Normal location commands would involve accessing coarse/fine location. Does anyone know what kind of extra commands this permission allows the app to access ?
Thanks.
I only know of 1 command which can be uses when you have a slow GPS fix:
((LocationManager)YourActivity.this.getSystemService("location")).sendExtraCommand("gps", "delete_aiding_data", null);
and in the Manifest:
<uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
According to a rough search in Android source code, it indicate that LocationManager.sendExtraCommand() need this permission exactly.
Documentation: sendExtraCommand(java.lang.String, java.lang.String, android.os.Bundle)
Go to https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/location/provider/AbstractLocationProvider.java;drc=master;bpv=1;bpt=1;l=353, click on onExtraCommand if you don't see the "References" panel at the bottom, scroll down to "Overriden By", and click on each implementation to see what commands it supports.
Here's a list of commands supported by GnssLocationProvider (since all of the other implementations seem to do nothing or delegate to another one):
delete_aiding_data: calls deleteAidingData
force_time_injection: calls requestUtcTime
force_psds_injection: sends a DOWNLOAD_PSDS_DATA message if mSupportsPsds is true
request_power_stats: calls requestPowerStats