This is my problem:
I have an application that requires a certain persmission (Write-SMS) that will of course only function on phones. Now, the app requires that permission for a feature that will be disabled on tablet versions but it won't let users install the app on tablets.
I guess my question is this:
Can I easily create a second manifest for the tablet version, that will be roughly the same as the phone version but without the persmission?
If I'm doing so, is there a way to check what manifest version is being used? I might want to add features to the tablet version that are tablet exclusive and vice versa.
All of course preferibly in one apk, that gets exported and signed once. Thanks for your help in advance!
Simple add:
<uses-feature android:name="android.hardware.telephony" android:required="false" />
To your manifest. The SMS permission automatically asks for a Telephony feature. Adding this tells android that even though you ask for this feature, you don't need it.
Be sure to add an if-else check to see if you can sens SMS from the device before doing so.
I think you must check it in the actual method itself, because permissions can be optional or compulsory, but that's it, not distinguishable for different devices..
Related
I'm trying to write an app that will start casting the screen from an Android phone to a TV via miracast. I'm using an HDMI dongle since the TV in question doesn't natively support miracast. I have been trying the code here, but it needs an Application ID which I have got following these steps. My question is, the instructions seem to indicate that I need to register the miracast dongle so it will talk to an unpublished 'debug' app. However, only Google Cast devices are mentioned and that isn't the same protocol as miracast. Do I still need to register the dongle?
Is there a simpler way of programmatically casting to a device via miracast? A requirement is no user interaction, so I can't just display a cast button.
I'm using Android 5.1 if that's relevant.
EDIT: After further research, I realized that Google Cast uses a completely different protocol from Miracast, and thus all the talk of registering the dongle is irrelevant. No registration is required at all to do Miracast in Android. The issue is the API is hidden, see my answer below for details.
So this is possible, but only on custom versions of Android due to permission problems.
What you need to use
The hidden part of the WifiDisplay API makes it all possible. This file contains examples of how to use the API to cast the display. It appears that Google will release it publicly at some point, although it's still hidden in the latest master of API 23 as far as I can see.
How to access the hidden API
To use hidden APIs, this guide(mirror here) provides a good introduction. If you're using API 22+ however, then that guide won't work as the format of android.jar has changed and classes.dex has been split across multiple files. So this advice is more accurate in that case. Note that the postscript about framework-classes2.dex must also be done; it isn't optional.
The latest version of the dex2jar tool fails to turn the .dex file from API 22 into a jar. The solution is mentioned by the author here. I opted to patch the tool instead of changing the dex, as that didn't work for me. Simply change the line the author mentions from throwing a RuntimeException to:
return TypeClass.INT;
How to get permission to use the hidden API
Once that is all done, the next step is giving your app the CONFIGURE_WIFI_DISPLAY permission. Unfortunately, as you can see here, it has system-level protection. This means that your app must be signed by the same key as the system to use this permission. So unless you have Google's private key, you can't have your app run on normal Android phones. My solution was to build a custom version of CyanogenMod(using this guide), with the permission changed from 'system' to 'normal'. This eliminates the need to bother with signing anything. I also did the same for the CONTROL_WIFI_DISPLAY permission. Whilst I'm not entirely sure this is necessary, it doesn't hurt. Both these permissions are located in frameworks/base/core/res/AndroidManifest.xml. Change the lines 2161-2169 from:
<permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
android:protectionLevel="signature" />
<permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
android:protectionLevel="signature" />
To:
<permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
android:protectionLevel="normal" />
<permission android:name="android.permission.CONTROL_WIFI_DISPLAY"
android:protectionLevel="normal" />
Then build CyanogenMod as normal. I can confirm this does work, but this limits your app to running on devices which have this custom version of CyanogenMod installed. Furthermore, installing CyanogenMod on an Android phone will generally invalidate the warranty.
try {
startActivity(new Intent("android.settings.CAST_SETTINGS"));
return;
} catch (Exception exception1) {
Toast.makeText(getApplicationContext(), "Device not supported", Toast.LENGTH_LONG).show();
}
hope this will help you, done screen mirroring with the cast settings, it uses your device's cast service. but you have to connect with same wifi both device and tv.
I've mentioned the following permission:
<uses-permission android:name="android.permission.NFC" />
in my manifest.xml. But NFC code is no more in use and I commented the source code. Means NFC is no more in use for my app, but while installing the app, it's still shows in installing window.
So, is it possible in android that don't ask for permissions mentioned in Manifest.xml file, if code is not in use? Thanks
No, it is not possible, because the Android system has no idea which permissions your application requires before run-time. Picture the following scenario:
You are writing an application, not specifying NFC permission as you're not using it in your code, but you ARE using a framework that in 50% of the implementations do use NFC (device manufacturer specific framework).
The Android system has no way of telling if the NFC permission is required and thus it relies on your explicit instruction for permissions
As I'm sure you've noticed, an exception will be raised if the permission does not exist for the specified action
The only way to make sure the requirement is gone is to remove the permission from the manifest (and frankly, is it that much of a deal?)
Besides commenting out the unnecessary codes, you have to remove the permission from your manifest as well.
I have added the following line into the manifest file but Play Store still shows Microphone in the features and it also says "XX devices removed" for the new APK file. (because of the microphone requirement)
<uses-feature android:name="android.hardware.MICROPHONE" android:required="false"/>
What can be the problem?
You still are requesting that you are using the feature but saying the device does not need the feature to use the app.
therefore the feature will show up because you still use it even though you dont require it.
If you dont want it to show then dont use the microphone
Most likely this is because you're using android.hardware.MICROPHONE instead of android.hardware.microphone. Hardware features are all lowercase.
Since it's not finding a matching <uses-feature> tag, it uses the implicit feature from the RECORD_AUDIO permission.
Is it possible at application level? Or do we have to do it inside the OS?
People might want to do this to reduce the attack surface. Ideally, the application, at virtually any point of time, should have a permission only if it is needed, following the `principle of least privilege'.
To clarify: by "change", I mean to give up certain permissions temporarily, and regain them sometime later when they are really needed.
Is it possible at application level? Or do we have to do it inside the OS?
You cannot change the permissions of your application dynamically, ever.
It would be against clarity Android policys . The application has or not has the permisions for doing something . It can be a security problem if you can think of it.
Officially this is not supported.
Newer CyanogenMod builds support "revoked permissions", but applications often force close if they lose permission they were supposed to have.
We're currently revising our application manifest to explicitly use the uses-feature attribute to declare all its dependencies on hardware and software APIs.
Since we expect the user to have mobile Internet, we set android.hardware.telephony to true, but now the app fails to install on the emulator. The error message is:
Failure [INSTALL_FAILED_MISSING_FEATURE]
There is no additional information, not even in the device logs, but I could figure out by trial and error that the telephony feature was causing it.
Since the emulator has support for telephony functionality (you can even simulate dispatching a call), why does this break? And even if it correctly reports that it doesn't support telephony, shouldn't it be obvious that uses-feature was meant to target real devices, not the emulator?
I'm actually quite confused about this attribute now in general, since its documentation seems to imply that it only affects filtering rules for Android Market. I can't see where it mentions that uses-feature has a direct impact of the installability of an app, which seems to go way beyond the merely declarational/informational nature the docs attribute to it.
Maybe it's not a good idea to use it after all? Our build server doesn't execute anymore, since installation to the emulator now always fails...
Basically what you need to use a more recent Emulater with more features supported,or alternatively you can do the following :
1.Comment out or remove the following lines from your Manifest XML file
<!-- COMMENT ME -->
<uses-feature android:name="android.hardware.telephony" />
OR
2.Add the following :
<!-- UNCOMMENT ME and add android:required="false" -->
<uses-feature android:name="android.hardware.telephony" android:required="false"/>
You should be good to go if you do it correctly.
I have an app that uses telephony and works fine with the 2.2 emulator and I presume you have already set the required attribute to false in your manifest:
<uses-feature android:name="android.hardware.telephony" android:required="false"/>
If that's the case, my guess is that there is another feature or permission declared in your manifest that isn't present in the emulator and causing the error. Hunt it down through trial and error.