AndroidTestCase - assertActivityRequiresPermission and assertReadingContentUriRequiresPermission - android

hoping for some help with the methods assertActivityRequiresPermission and assertReadingContentUriRequiresPermission. It's not behaving the way I thought it will and I'm not seeing where I went wrong.
My understanding is that both activities and providers can be protected by adding android:permission to their respective tags ( and ) in AndroidManifest.xml. To declare that a client activity has the required permission to start and activity or work with a provider, we declare under the tag in what I believe to be at a 'package' level.
So to test how the assert methods in AndroidTestCase works I set up a HelloWorld project and a project to test HelloWorld. This is the manifest for HelloWorld.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.helloandroid"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".HelloAndroidActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".RecipientActivity"
android:label="#string/app_name"
android:permission="android.permission.RECEIVE_SMS" >
</activity>
</application>
</manifest>
I have RecipientActivity protected by RECEIVE_SMS, so I declare using RECEIVE_SMS so that HelloAndroidActivity is able to start RecipientActivity.
Now in my test class,
public class TestRecipientActivity extends AndroidTestCase {
public void testPermissions() {
String packageName = "com.example.helloandroid";
String className = packageName + ".RecipientActivity";
String permission = android.Manifest.permission.RECEIVE_SMS;
assertActivityRequiresPermission(packageName, className, permission);
}
public void testContactsPermissions() {
final Uri URI = ContactsContract.AUTHORITY_URI;
final String permission = android.Manifest.permission.READ_CONTACTS;
assertReadingContentUriRequiresPermission(URI, permission);
}
}
Results?
testPermissions() fails with 'AssertionFailError: expected security exception', meaning RecipientActivity is started successfully with no SecurityException thrown.
testContactsPermissions() passed without throwing any exception although I do not have define anywhere.
Can anyone explain why I'm getting the above results? Thanks!

You asked this question long time ago and I don't know if you have already solved it.
I am learning Unit-Testing in Android and I had the same problem. At the beginning I thought that the method assertActivityRequiresPermission() tests the permissions declared in < uses-permission >, but then I realized that this method only test if there is a specific permission associated to the activity passed as parameter.
You are associating the same permission to the < uses-permission > and < activity > tags. The point is that the assert works if you delete the permission from < uses-permission >. I think the problem is that this assert is expecting a SecurityException caused because it can't launch the activity without the permission, but you are using that permission in the manifest.xml, so the exception is not thrown.

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 Permissions - Best Practices

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.

Is it possible to have an Activity over a NativeActivity and still getting inputs in the NativeActivity?

I have a NativeActivity which works by itself and I try to add some SDKs ( more precisely Admob/Chartboost/Facebook ).
On the other hand I've got custom scripts which manage all the SDK only if we pass an Activity in the parameters.
My goal is to manage all of the SDKs with a custom Activity over my NativeActivity.
My questions :
Is It even possible ?
Is there a simpler solution than mine ?
So far my inputs are stucked in the Activity.
Here's my NDK class ( from the android-ndk examples ) :
public class TeapotNativeActivity extends NativeActivity {
// Some previous code
public void showUI()
{
// Some previous code
ASE_GUIActivity.pNatAct = this;
Intent startNewActivityOpen = new Intent(this, ASE_GUIActivity.class);
this.startActivity(startNewActivityOpen);
}
}
Here's my activity class :
public class ASE_GUIActivity extends Activity {
public static NativeActivity pNatAct;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public boolean onTouchEvent(MotionEvent ev) {
pNatAct.onTouchEvent(ev);
return super.onTouchEvent(ev);
}
}
And finally my AndroidManifest.xml :
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sample.teapot"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="17" />
<uses-feature android:glEsVersion="0x00020000"></uses-feature>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme"
android:hasCode="true"
android:name="com.sample.teapot.TeapotApplication"
>
<!-- Our activity is the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity android:name="com.sample.teapot.TeapotNativeActivity"
android:label="#string/app_name"
android:configChanges="orientation|keyboardHidden">
<!-- Tell NativeActivity the name of or .so -->
<meta-data android:name="android.app.lib_name"
android:value="TeapotNativeActivity" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.littleworlds.ase.ASE_GUIActivity"
android:theme="#android:style/Theme.Translucent"
android:screenOrientation="landscape"
android:configChanges="keyboard|keyboardHidden|orientation"/>
</application>
</manifest>
As far as I know, you can not instantiate an activity inside an activity. You can only use intent mechanism, in which case you will only have one activity running at the same time. Your design choice does not seem suitable for Android environment.
Why don't you try to launch the SDK activities you mention from native side? For example, if you want to launch a Facebook login screen when user clicks a button, get the necessary input inside native activity and then using JNI calls and intent mechanism, launch the Facebook activity.

Enable communication between two Android apps via custom permissions

One of my Android applications needs some features that are "dangerous" when it comes to permissions. They require some permissions such as "Internet access" which are critical in combination with private data.
This is why I want to create a separate "Add-on", i.e. a second app that provides these permission-critical features. So if users want them, they can install the add-on, but the main app will still work without those permissions.
Using a sharedUserId would obviously be the easiest solution, but adding this afterwards, when lots of users use the app already, could cause serious problems. Wouldn't this mean that the app can't access its own data any longer?
So I have to choose another approach. ContentProviders are something that I try to avoid, because they're too complex for this simple need in my opinion.
I thought custom permissions could solve the issue. Can they? I've added the following permission declaration to both the main app as well as the add-on as a child to the manifest tag in AndroidManifest.xml:
<permission
android:name="com.my.package.ADDON"
android:label="#string/permission_title"
android:description="#string/permission_description"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:protectionLevel="signature" />
Furthermore, both manifest files have got this part now:
<uses-permission android:name="com.my.package.ADDON"></uses-permission>
The add-on app includes an IntentService that has the following attribute now:
android:permission="com.my.package.ADDON"
Shouldn't this do the job so that I can call the add-on's IntentService from my main app via this code?
Intent addonIntent = new Intent();
addonIntent.setClassName("com.my.package", "com.my.package.MyService");
startService(addonIntent);
Unfortunately, this call always fails with the following exception:
E/AndroidRuntime(16721): java.lang.SecurityException: Not allowed to start service Intent { cmp=com.mypackage.addon/.MyService } without permission com.mypackage.permission.ADDON
What did I do wrong? Thank you very much in advance!
Addition #1 - Add-on manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="com.mypackage.addon">
<uses-sdk android:minSdkVersion="8" />
<permission
android:name="com.mypackage.permission.ADDON"
android:label="#string/permission_title"
android:description="#string/permission_description"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:protectionLevel="signature" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:permission="com.mypackage.permission.ADDON"
android:exported="true">
<service
android:enabled="true"
android:name=".MyService" />
</application>
</manifest>
Addition #2 - main app manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0"
package="com.mypackage.mainapp">
<uses-sdk android:minSdkVersion="8" />
<permission
android:name="com.mypackage.permission.ADDON"
android:label="#string/permission_title"
android:description="#string/permission_description"
android:permissionGroup="android.permission-group.PERSONAL_INFO"
android:protectionLevel="signature" />
<uses-permission android:name="com.mypackage.permission.ADDON"></uses-permission>
<application android:icon="#drawable/ic_launcher" android:label="#string/app_name" android:name="MyApp">
<activity android:name=".MainActivity" android:launchMode="singleTask" 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>
Wouldn't this mean that the app can't access its own data any longer?
Correct.
I've added the following permission
I would dump the permission-group, as that should not be necessary.
Furthermore, both manifest files have got this part now
Only the one calling your IntentService might need that.
Shouldn't this do the job so that I can call the add-on's IntentService from my main app via this code?
Not if that IntentService is not exported. Make sure that your IntentService either has an <intent-filter> or android:exported="true". I would recommend going the <intent-filter> route, so you can declare and use a custom action string, so you get away from hard-coding package and class names in the client app.
Here is a directory with two sample projects using this basic approach, though in my case the communications are based on a secured ContentProvider rather than a secured IntentService. The concept is the same, though, and so with these minor tweaks, I would expect what you are doing to work just fine.

ServiceTestCase is not launching my service

I am attempting to write some JUnit tests for my android application. The application is a service.
I have tried several things to get the ServiceTestCase to launch the service but it fails to.
HOWEVER, when i debug the ServiceTestCase it WILL launch the service. I belive this is because the ServiceTestCase is calling setup and not giving enough time for the service to launch before it kills it...
I am not completely sure, this is the first time i have ever used junit testing for android. VERY new to this. Any suggestions on what i can do to fix this problem?
I was thinking of creating some timer loop or something, but that seems REALLY dirty. Would like a much cleaner aproach.
Android Manifest for the service.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dataservice.server"
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application android:icon="#drawable/icon" android:label="#string/app_name">
<service android:name="dataservice.server.DataServer" android:process=":remote" android:exported="true" android:enabled="true">
<intent-filter>
<action android:name="dataservice.DataService.BIND.1" />
</intent-filter>
<intent-filter>
<action android:name= ".DataServer" />
</intent-filter>
</service>
<receiver android:name="dataservice.server.Receiver">
<intent-filter>
<action android:name="android.intent.action.USER_PRESENT"></action>
<action android:name="android.intent.action.BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
</application>
</manifest>
The ServiceTestCase i am attempting.
public class Publish extends ServiceTestCase<DataServer> {
private final static String TAG = "Publish Unit Test";
private Context mSystemContext;
public Publish() {
super(DataServer.class);
}
public Publish(Class<DataServer> serviceClass) {
super(serviceClass);
}
#Override
protected void setUp() throws Exception {
// TODO Auto-generated method stub
super.setUp();
// this is where i am attempting to start the service.
// i have attempted other methods, but none of those worked either.
startService(new Intent(this.getContext(), DataServer.class));
}
public void testPublish() {
}
}
I was referencing one of the dependant projects incorrectly. Once this was fixed, it resolved the issue. So, check and make sure you are referencing your projects correctly if you are having the same issue.

Categories

Resources