Android Permissions - Best Practices - android

I have two Android Applications, a permission provider and a requester.
The provider has the below manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.permissionprovider"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<permission android:description="#string/permission_desc"
android:icon="#drawable/ic_launcher"
android:label="some permission"
android:name="com.example.permissionprovider.CUSTOM"
android:protectionLevel="normal" />
<!-- is the below tag required in the provider?-->
<uses-permission android:name="com.example.permissionprovider.CUSTOM"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.permissionprovider.MainActivity"
android:permission="com.example.permissionprovider.CUSTOM"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
I hope it is wrong to set permissions to a launchable activity as the launcher won't have permissions to launch this activity.Is that correct?
Should the provider's manifest declare that the provider application needs the permission - com.example.permissionprovider.CUSTOM , or is it not required as the permission is defined in the same manifest?
Now I have the requester app which has the below manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.permissionrequester"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="com.example.permissionprovider.CUSTOM"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.permissionrequester.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
and the Requester tries to start the provider's activity.
Intent i;
PackageManager manager = getPackageManager();
try {
i = manager.getLaunchIntentForPackage("com.example.permissionprovider");
if (i == null)
throw new PackageManager.NameNotFoundException();
i.addCategory(Intent.CATEGORY_LAUNCHER);
startActivity(i);
} catch (PackageManager.NameNotFoundException e) {
} }
If the provider app was installed first followed by the requester, then the requester will be able to launch the provider's Activity, but this doesn't happen if it's the requester which is installed first. How to get around this?

I hope it is wrong to set permissions to a launchable activity as the launcher won't have permissions to launch this activity.Is that correct?
Correct, the launcher will be incapable of starting that activity. However, it will still appear in the launcher, and therefore the user will get frustrated when they cannot start up your app.
Should the provider's manifest declare that the provider application needs the permission - com.example.permissionprovider.CUSTOM , or is it not required as the permission is defined in the same manifest?
You can define the <permission> in both apps, to deal with your last problem:
If the provider app was installed first followed by the requester, then the requester will be able to launch the provider's Activity, but this doesn't happen if it's the requester which is installed first. How to get around this?
Define the <permission> in both apps.
Also, if you are publishing both apps, and no third parties should be using your provider, please use a signature-level permission, not a normal-one. This will prevent anyone other than you from writing an app that can successfully hold the permission.

Related

Android M Content Provider Permissions

I have seen similar questions, but I think I'm running into Android M specific trouble.
I have two Android applications. One extends ContentProvider to manage a SQLiteDatabase. The other presents a GUI and reads/writes data from/to the Content Provider. The two applications work together successfully until I try to set permissions on the Content Provider.
I receive the following error message:
Caused by: java.lang.SecurityException: Permission Denial: opening
provider com.example.productkit.ProductKit from ProcessRecord{ce096cd
27369:com.example.myapplication/u0a60} (pid=27369, uid=10060) requires
com.example.productkit.permission.CONTENT_PROVIDER or
com.example.productkit.permission.CONTENT_PROVIDER
The AndroidManifest.xml file for the Content Provider looks like this:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.productkit">
<permission android:name="com.example.productkit.permission.CONTENT_PROVIDER"/>
<application>
<provider
android:name=".ProductKit"
android:authorities="com.example.productkit"
android:exported="true"
android:permission="com.example.productkit.permission.CONTENT_PROVIDER"/>
</application>
</manifest>
The AndroidManifest.xml file for the GUI application looks like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">
<uses-permission android:name="com.example.productkit.permission.CONTENT_PROVIDER"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
My understanding is that the application needs to request permission(s) at run time with Android M. As an experiment, I've tried to do that with the following test code:
int hasPermission = checkSelfPermission("com.example.productkit.permission.CONTENT_PROVIDER");
if (hasPermission != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[] {"com.example.productkit.permission.CONTENT_PROVIDER"},
REQUEST_CODE_ASK_PERMISSIONS);
}
hasPermission = checkSelfPermission("com.example.productkit.permission.CONTENT_PROVIDER");
Unfortunately hasPermission does not equal PERMISSION_GRANTED following the call to requestPermissions().
If I use the same code to gain access to a built-in permission, like to the CAMERA, a dialog appears and I can grant permission to the application. That behavior does not happen for my Content Provider's permission.

Android: get current device location without asking permission at run time

I've created a hospital related app where i want to know the whether patient has visited the doctor or not, getting the location is the requirement of my app.
I've used ACCESS_COARSE_LOCATION and ACCESS_FINE_LOCATION permission in manifest. The problem is whenever application tries to get the location at run time the system prompts a security dialog which says "this app is trying to obtain your current location" and asks user to allow or deny it,, and if user clicks on the deny button the location is not fetched..
I don't want the user to click on the deny button is there any way i can skip this security dialog and set 'always allow' option in my app permission through code and get the location without ever prompting the user for access.
manifest file
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.kaizen"
android:versionCode="4"
android:versionName="1.1" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="22" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
android:name="com.kaizen.volley.VolleySingleton"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.kaizen.SplashScreen"
android:configChanges="keyboardHidden"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.kaizen.Login"
android:windowSoftInputMode="stateHidden|adjustResize" />
<activity
android:name="com.kaizen.AppMenu"
android:screenOrientation="landscape"
android:windowSoftInputMode="stateHidden|adjustResize" />
<activity
android:name="com.kaizen.SignUp"
android:windowSoftInputMode="stateHidden|adjustResize" />
</application>
The dialog you're seeing surely is a vendor specific feature. E.g. there is some function called KNOX for Samsung business devices, that seems to behave like what you're seeing. Once you found out where it comes from exactly, I wouldn't care about it any further. This is not widely spread and in those cases where the message pops up it will do for a reason: the user wants (or is forced by his administrator) to be informed about certain actions, such as apps wanting to get the current location.
You may check the normal behavior of your app in an emulator, if you do not have another device.

No activity found to handle Intent - android.intent.action.OPEN_DOCUMENT

I am trying my hand on Storage Access Framework of android 4.4
I have developed a dummy app which fires an intent on start of the activity.
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, READ_REQUEST_CODE);
Also I have developed another dummy app which serves as the file-provider.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.saf"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="19"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.saf.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="com.example.saf.MyFileProvider"
android:authorities="com.example.saf.documents"
android:exported="#bool/is_kitkat"
android:enabled="#bool/is_kitkat"
android:grantUriPermissions="#bool/is_kitkat"
android:permission="android.permission.MANAGE_DOCUMENTS">
<intent-filter>
<action android:name="android.content.action.DOCUMENTS_PROVIDER" />
</intent-filter>
</provider>
</application>
I have implemented the class MyFileProvider.
But when I launch the user-app (the one which fires the intent), I get the following error
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.OPEN_DOCUMENT cat=[android.intent.category.OPENABLE] }
I was just following developer docs of android. Any ideas what I might be doing wrong?
Edit:
Here is my latest Manifest.
Also do I need to have a "proper" implementation of the MyFileProvider "extends DocumentsProvider"? Can I just return null in the functions for now?
Add a mime type, or simply intent.setType("*/*").
This seems to be a known issue. setType() is required.
Edit: you also need to add android:enabled="true", note that you should reference it from values and not directly so as only to enable it for >=kitkat. So android:enabled="#bool/is_kitkat", <bool name="atLeastKitKat">false</bool> in /res/values/ and <bool name="atLeastKitKat">true</bool> in /res/values-v19/
To open all files add this line:
intent.setType("*/*") ;
and if you need to filter to display images add this line:
intent.setType("image/*");
Just cast your intent,
like,
Intent intent = new Intent("android.intent.action.GET_CONTENT");
((Intent)intent).addCategory("android.intent.category.OPENABLE");
((Intent)intent).setType("*/*");

Android app doesn't launch the main activity and says app isnt installed

So im kinda new to android programming and i dont really know why i cant run the main activity when i have a permission tag under the activity. this is my code under the manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.lab08b_awahla"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="com.example.DANGEROUS_ACTION" />
<permission
android:name="com.example.DANGEROUS_ACTION"
android:label="permission"
android:protectionLevel="dangerous" />
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name="com.example.lab08b_awahla.MainActivity"
android:label="#string/app_name"
android:permission="com.example.DANGEROUS_ACTION" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="com.example.DANGEROUS_ACTION" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
This is obvious. If you are providing a security tag for activity anyone who wants to launch this activity has to have such privilege. Home screen app doesn't have (even don't known) your permission tag so this is a problem.
According to the docs for the <activity> tag
android:permission
The name of a permission that clients must have to launch the activity or otherwise get it to respond to an intent. If a caller of startActivity() or startActivityForResult() has not been granted the specified permission, its intent will not be delivered to the activity.
This leads me to think that you misunderstand the use of this attribute.

android content activitynotfoundexception no activity found to handle intent - when trying to go to url

I am trying to write an app where you can type in an address and then you get redirected to google maps. (I suppose this is called implicit intent)
-I have created an intent to launch the main activity, which is the only activity in my app.
The Main activity consists of some text, an editfield and a button.
AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.where_do_you_live"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
this is the code for the button:
public void Button1Click(View view)
{
try
{
addressField=(EditText)findViewById(R.id.address);
String address=addressField.getText().toString();
address=address.replace(' ','+');
Intent geoIntent=new Intent(android.content.Intent.ACTION_VIEW,
Uri.parse("geo:0,0?q=" + address));
startActivity(geoIntent);
}
catch(Exception e)
{
TextView tv=(TextView)findViewById(R.id.textView1);
tv.setText(e.toString());
//finding stuff
}
}
If you are testing this in emulator, things are different than in a device.
When you are creating your Android Virtual Device, you should select Google APIs as your target. If you do not have them installed, you can use SDK Manager to download it.
Have a look at this.

Categories

Resources