Steps to programmatically cast from android to miracast receiver

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.