tomloprod / cordova-plugin-fakelocation

FakeLocation is a cordova plugin to check if "Allow mock locations" are enabled or disabled in android devices.
MIT License
5 stars 13 forks source link

How to check whether any app is set to use slected Mock Locations setting or not in Android Marshmallow #1

Open mohanchalla opened 7 years ago

mohanchalla commented 7 years ago

In Android Marshmallow the plugin is always returning true.

tomloprod commented 7 years ago

I cannot try right now, but maybe using a loop of installed apps and check if any of this is selected as mock location app would work. I cannot try the next code, but I think something like this will work for Marshmallow:

//////////// Package manager
final PackageManager pm = getPackageManager();

//////////// List of all installed apps.
List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);

//////////// AppOpsManager
AppOpsManager opsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);

boolean isMockEnabled = false;

for (ApplicationInfo packageInfo : packages) {
     //////////// The package name.
     String packageName = packageInfo.packageName;

     //////////// I think this will get the UID
     int UID = packageInfo.uid; 

    //////////// Check this app is selected as mock location app
    if(opsManager.checkOp(AppOpsManager.OPSTR_MOCK_LOCATION, UID, packageName) == AppOpsManager.MODE_ALLOWED){
        isMockEnabled = true;
    }

}

If this works (I cannot try right now) I will combine this block with my current code for Android < 6.0

mohanchalla commented 7 years ago

@tomloprod what is this mContext where is the object creation for this? getPackageManager() without reference will it work?

tomloprod commented 7 years ago

Inside the cordova plugin, you can get the context with:

Context mContext = this.cordova.getActivity().getApplicationContext(); 

getPackageManager() should work. See this stackverflow answer.

mohanchalla commented 7 years ago

final PackageManager pm = getPackageManager(); ^ symbol: method getPackageManager() location: class FakeLocation D:\projects\mo-jess\platforms\android\src\tomloprod\fakelocation\FakeLocation.java:25: error: cannot find symbol

and uid is an integer value

mohanchalla commented 7 years ago

I find the solution in this http://stackoverflow.com/questions/22396382/cant-find-getpackagemanager-method-in-android

tomloprod commented 7 years ago

Perfect. Yes uid is an integer. (As I said, I cannot try this right now)

mohanchalla commented 7 years ago

After adding the code whatever you have suggested me. I am getting following error. uid 10214 does not have android.permission.UPDATE_APP_OPS_STATS. Do I need add any permission for this?

tomloprod commented 7 years ago

Hmmm, I don't know this permission. Try to add this in plugin.xml:

<config-file target="AndroidManifest.xml" parent="/*">
    <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS"/>
</config-file>
mohanchalla commented 7 years ago

While iterating installed apps, If any of the app has not updated with this permission then we will get this exception I think so. Even If I add for this plugin there will be no use. Because while iterating the apps, lets say we got first object is fake GPS then this app has have UPDATE_APP_OPS_STATS permission.

tomloprod commented 7 years ago

I thought you got that exception out of the loop, on this line:

AppOpsManager opsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);

Well... If what you said it's true, there is no way to check if there is an application marked as mock location app. At least, not by the means we have tried...

mohanchalla commented 7 years ago

Yes! Even I am also thinking There no way to check by iterating all installed apps and checking the permissions of the other apps. I think we can not do that in android because we can see the permissions of another apps from our application.

tomloprod commented 7 years ago

Maybe it's possible to see the permissions of another apps. See this: http://stackoverflow.com/questions/5385957/how-to-get-apps-permission-for-each-app-how-to-do-it-programmatically-on-andro#14672557

mohanchalla commented 7 years ago

But these permission will be set at the time of installation requested by the app to the user. User will select the particular app to mock the locations right? I don't think for this any permission will set. And one more issue is there, If the user has rooted his phone then without changing settings he spoof the GPS Coordinates. check the below link to get the app permissions http://stackoverflow.com/questions/6880232/disable-check-for-mock-location-prevent-gps-spoofing

tomloprod commented 7 years ago

Root devices can do all. I'm thinking of NO rooted devices. Anyway I only answer your question:

I think we can not do that in android because we can't see the permissions of another apps from our application.

I guess the way to check if the devices is using mock locations in Android Marshmallow is using the isFromMockProvider method of location, but as I know this isn't 100% relaible... And we are on Cordova, so we cannot have the android Location object.

Maybe the solution goes through to change the code you are use to get the location (cordova-plugin-geolocation, cordova-plugin-background-geolocation, ...) and return, with the coordinates, a boolean. Lot of work for something like this... But if its a requirement, is the only way to do that, I guess.

rafialikhan commented 7 years ago

Any progress on this? This is a great plugin just that it doesnt work on Marshmallow and above, which is 98% of our target users.

tomloprod commented 7 years ago

@rafialikhan I have not had time to inquire into this problem. I think the solution is to implement the "[isFromMockProvider](https://developer.android.com/reference/android/location/Location.html#isFromMockProvider())" method in the plugin that provides the locations.