Since the time I have the Vive Focus of Mr. President on my desk, I’ve started doing experiments with it and its Vive Wave SDK. For instance, I contributed to the little musical experience that Enea Le Fons has taken to a disco club during his 30 Days in VR experiment and I made the porting of the ImmotionRoom full-body VR system to the new HTC device. In all my journey, there has been a big nuisance that has stopped me from running apps on the device: requesting Android permissions. This is something that in my opinion is not straightforward on the Focus unless someone tells you how to do it (I’ve been helped by some HTC’s engineer), so I wanted to guide you in this process.
Android Permissions
The Vive Focus is an Android device and to be exact, it currently runs Android 7.0. Of course, it is not the standard Android with the standard Android UI (it’s all in VR, here!), but the basis is the same. That’s why in my post describing you how to stream Focus content on an external screen, I described methods that can be used with any other Android phone.
On Android, all apps using special features of the device (Bluetooth, Camera, Internet connection, etc….) must request them to the operating system. In the past, this meant just highlighting these features inside the Android Manifest of the app, using the <uses-permission> tag. When the application was installed, the operating system asked for permissions to the user before installing the app and these permissions were granted forever and ever (eh, good times for us devs).
Since Android 6.0, things have changed a lot. First of all, the permissions have to be requested at runtime and not at install time. This means that the user has to accept them during the execution of the app and can also revoke the authorization at any time. Then, the permissions have been divided into two categories: normal and dangerous. “Dangerous” permissions are the ones that could be used to harm the user in any way (e.g. “Camera”, that can be used by the app to silently film the user), while all the other ones are considered “normal” (e.g. “Bluetooth”, that apart from being a problem itself, usually isn’t used for attacks).
To request the permissions, the dev has still to specify them in the manifest. When the app gets launched:
- If the permission level is “normal”, the OS automatically grants it;
- If the permission level is “dangerous”, a pop-up asks the user if he wants to grant it. Notice that this means that if the user denies the permission, the app must still launch and be reactive to it (maybe disabling some-features or requesting the permission again prompting to the user that it is fundamental).
Permissions can also be asked by the dev during app execution, but now I don’t want to make things too much complicated. If you’re interested in all this permission stuff, you can read directly the related Android documentation.
Unity and Android Permissions
What does this mean if you want to request some permissions inside Unity? Basically, it means that you have to specify the features you want to request inside the Manifest of your app. Unity makes things easier for us, so whenever we use some Unity class that clearly needs a permission, Unity adds this permission automatically to the manifest. For instance, I recently made an AR app using Vuforia and at the first execution, the system asked me if I wanted to authorize the use of the camera. I added nothing to the manifest or to any other file, but since Vuforia clearly uses some Unity APIs to access the camera, that permission has been added automatically to the manifest by Unity itself. (Thanks, Unity)
For all non-standard uses, some nerdier work is needed: If you want to add custom permissions, you have to tweak the Manifest yourself and if you want to request some permission at runtime, you have to write a Unity native plugin for that. If you need more info on this process, here you are the Unity manual page dedicated to that.
Vive Focus and Android Permissions on Unity
Things on Vive Focus are similar but a bit different. First of all, we are in VR, so a 2D box on the screen of the device asking if we grant the permission can’t work. Then, HTC Vive has already added a custom manifest that gets imported when you import the Wave SDK Plugin. You can find it in the Assets\Plugins\Android folder of your project. In this file, you can notice that there is this line
<meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />
that is used exactly to prevent the 2D permission box to appear on the screen in the standard way, because it would make your eyes cross to see it. This also means that there is no more the standard way of granting permissions!
Furthermore, you may also notice that there are some commented lines regarding permissions, like this one
<!-- <uses-permission android:name="android.permission.CAMERA" /> -->
and that feels strange because they are commented. They are this way because they are the lines taken from the Wave SDK sample on permissions and you can ignore them (I don’t get why they don’t remove them from the manifest and leave them only in the sample).
So, we have already a manifest for our app and we have to tweak it to request the permissions. Notice that if you don’t ask for permissions on the Focus, the app just runs without having all the features you want: it doesn’t crash, it just doesn’t work and you don’t know why. I made the disco app and couldn’t get why the detected microphone volume level was always 0… and only in the end, I realized I needed the Microphone permission! So, if your Focus app doesn’t work the way you want to, ask yourself if you missed asking for some permissions.
But… how to ask them?
Standard permissions
In case of normal permissions like INTERNET, that I used to make the porting of ImmotionRoom to the Focus, it is usually enough to add them to the manifest, exactly where there are the other commented permissions. So, for the porting of ImmotionRoom, that needs Wi-fi to work, I added this line just before the last line of the AndroidManifest.xml provided by Vive Wave in the Assets\Plugins\Android folder:
<uses-permission android:name="android.permission.INTERNET" />
Notice that the commented uses-permission tags are completely useless, they are not parsed by external programs or such, so you can remove them if you wish. My manifest so looked like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application android:icon="@drawable/app_icon"
android:label="@string/app_name"
android:theme="@style/Theme.WaveVR.Loading"
tools:replace="android:theme"> <!--You can use your theme here.-->
<activity android:name="com.htc.vr.unity.WVRUnityVRActivity"
android:label="@string/app_name"
android:enableVrMode="@string/wvr_vr_mode_component">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="com.htc.intent.category.VRAPP" />
</intent-filter>
<meta-data android:name="unityplayer.UnityActivity" android:value="true" />
<meta-data android:name="unityplayer.SkipPermissionsDialog" android:value="true" />
</activity>
<meta-data android:name="com.htc.vr.content.NumDoFHmd" android:value="6DoF"/>
<meta-data android:name="com.htc.vr.content.NumDoFController" android:value="6DoF"/>
<!--Please consider the DoF support of HMD and controller individually for your content.-->
<!--Set value “3DoF” if your content only considers the rotation pose. -->
<!--Set value “6DoF” if your content considers both rotation and position pose. -->
<!--Set value “3,6DoF” if your content is capable of supporting both 3 and 6 DoF playing. -->
<meta-data android:name="com.htc.vr.content.NumController" android:value="2"/> <!--fill the value of how many controllers the application can support.-->
</application>
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
The only line that I’ve added is the one before the closing tag </manifest>, all the other ones are the standard ones created by the Vive Wave SDK. You can do the same for your permissions, adding all the requests you want exactly in that position of the file.
Launching it, everything worked. Full body VR for everyone!
But, what if you have to ask for a dangerous permission or if this method strangely doesn’t work? Well, you have to make your hands a bit dirtier…
Dangerous permissions
For standard permissions, it was easy. But what about if we have to request a dangerous permission, like the use of the Microphone? We know that there is not the possibility to show a standard Android pop-up to the user…
Well, in this case, you have to refer to this page of the docs of the Vive Wave SDK, where there is described the use of the WaveVR_PermissionManager. It is a class developed by HTC engineers to let you ask for runtime permissions.
The first step that the manual tells you regarding this process is installing the “PermissionService-release.apk” on the device. Inside the Wave SDK package, I only found an unsigned version of the APK, inside the <wave_sdk_folder>\SDK\services: I signed it with command line tools and then when I tried installing it on my Focus, the system answered me that it was already installed and that the update was incompatible (of course, before of the different keys). So, most probably this service is already installed on your device and you don’t have to do anything. If this is not the case for you, you have to sign that APK and install it on your Focus.
Then, you have to add the permissions to your Android manifest, as above. For instance, to have the microphone, I had to add
<uses-permission android:name="android.permission.RECORD_AUDIO" />
At this point, you have only done half of the job. To complete it, you have to:
- Ask permissions at run-time to the Android OS through the WaveVR_PermissionManager;
- Wait for the permissions to be granted;
- Execute the program normally.
Ath the Wave docs page, there is an example script to do that, but I want to suggest a slightly different approach. First of all, since you just want to request these permissions only once at the program startup, I’d just add an initial scene that is used only to request permissions and then go on to the main scene only when the permission is granted. This makes things easier for the dev: if you’re in the main scene, you’re sure that the permissions have been granted and you can execute your program normally, without stopping all the scripts until the permission has been granted. If you’re in the permissions request scene, it means that you’re still in the process of getting the authorizations. IMHO, it is cleaner.
Before giving you the code to do that, download from GitHub a script called UnityMainThreadDispatcher.cs and add it to the project. I’ll explain its use in a while.
Then, inside your Unity project, where you have already added the Vive Wave SDK, create a new scene and call it PermissionsRequest and leave there just a Camera that shows a monochrome background, remove the Main Camera gameobject and substitute it with a WaveVR prefab (you can find it in Assets\WaveVR\Prefabs). We’ll use this scene to request permissions, moving to the main one only when the authorizations will be granted. Create a new empty game object in this scene and call it “PermissionsManager”. Add to it the UnityMainThreadDispatcher behaviour you just downloaded.
Then create a new C# script and call it RequestPermissions and add it to the PermissionsManager gameobject, too.
Open the just created script and substitute it with this code, that will ask for the permission of the Microphone (feel free to tweak it to request the permissions that you need):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
/// <summary>
/// Request Android permissions
/// </summary>
public class RequestPermissions : MonoBehaviour
{
/// <summary>
/// Instance of the permissions manager
/// </summary>
private WaveVR_PermissionManager pmInstance = null;
private void Start()
{
//call the permission manager only if we're running the application on an Android device (the Focus), otherwise just go the main scene of the game
if (Application.platform != RuntimePlatform.Android)
{
GoToMainScene();
}
else
{
pmInstance = WaveVR_PermissionManager.instance;//get the permission manger
StartCoroutine(PermissionManagerWait());
}
}
/// <summary>
/// Waits the permission manager to be ready and then asks for a permission
/// </summary>
/// <returns></returns>
private IEnumerator PermissionManagerWait()
{
//list of the permissions necessary for this application. Here i just need the microphone
string[] tmpStr =
{
"android.permission.RECORD_AUDIO"
};
//wait for the permissions manager to be initialized, without blocking the app
while (!pmInstance.isInitialized())
{
yield return new WaitForSeconds(0.33f);
}
//Major function to request permission
pmInstance.requestPermissions(tmpStr, requestDoneCallback);
}
/// <summary>
/// Callback called when the permissions manager has had the results of its requests
/// </summary>
/// <param name="results"></param>
private void requestDoneCallback(List<WaveVR_PermissionManager.RequestResult> results)
{
//if the user has granted the mic request, go to main scene, otherwise log the failure
if (results[0].Granted)
UnityMainThreadDispatcher.Instance().Enqueue(() => { GoToMainScene(); });
else
UnityMainThreadDispatcher.Instance().Enqueue(() => { Debug.Log("WTF user"); });
}
/// <summary>
/// Go to the game main scene
/// </summary>
void GoToMainScene()
{
SceneManager.LoadScene("GameMainScene"); //we're ready for the real game action
}
}
I’ve commented it enough to let you understand easily the code, but there are some passages I want to highlight:
- You have to go through the permission manager only if you’re executing on the device, otherwise just go to the main scene. The permission manager uses a native plugin, so it can’t work in the editor. Here I’ve chosen a runtime approach (if (Application.platform != RuntimePlatform.Android)), but you can also use #if UNITY_ANDROID && !UNITY_EDITOR conditional programming clause;
- You have to specify all the permissions you need inside a string array. These strings must represent the exact strings you wrote in the manifest: for the microphone, it is android.permission.RECORD_AUDIO;
- You have to wait for the permissions manager to initialize itself and only at that point ask for the permissions;
- At this point, the system will show a 2D box IN VR to the user, that is different from the standard Android OS one; the user may grant or deny the permissions by using gaze or the Focus remote;
- Once the user has answered to the pop-up, the callback requestDoneCallback will be called, with the results of all the permissions requests. Here I am just requesting one, so I just check the first element of the list, going to the main scene only if it has been granted. If the user doesn’t grant the permissions, you have to implement some logic showing him that he made the wrong choice. Here I just logged the problem and halted the program there… in production, this is not a smart choice;
- Notice that in the callback, I haven’t just written GoToMainScene(), but I made all that complicated stuff with Enqueue(). Why?? Because I’ve noticed that this callback can be called on a non-UI thread, so if you want to call Unity main thread, you have to use the UnityThreadDispatcher I’ve made you download. This guarantees that all the code will be executed on the Unity main thread. If you don’t do this way, things do not work if you try to call various Unity methods. For instance, in one my first implementations, I tried to call a Gameobject.Find inside this callback and the program halted without telling me why. Looking inside LogCat, I discovered that there was a threading issue.
As you can see, once you know how to do that, it is all matter of cutting and pasting this code into every Vive Wave app you need. Maybe you can create your custom permissions requesting scene and use it in all programs you develop. Cool, isn’t it?
You may wonder what happens when you use this complicated procedure even for the “normal” permissions and the answer is: nothing, the permission just gets granted immediately, without the user having to accept anything.
Building and running the app, I had my cubes reacting to the microphone volume! It was incredible…
I hope this posts will help people having problems in asking for Android permissions inside the Vive Focus. If it has helped you or you know someone who may be interested, would you mind sharing it on your social media channels? I give you the permission to do that…