├── .classpath ├── .gitignore ├── .project ├── AndroidManifest.xml ├── README.md ├── ic_launcher-web.png ├── libs └── android-support-v4.jar ├── proguard-project.txt ├── project.properties ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-ldpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── layout │ ├── list_item.xml │ ├── local_display.xml │ └── remote_display.xml ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml └── values │ ├── strings.xml │ └── styles.xml └── src └── com └── adamrocker └── miracastsample └── MainActivity.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | gen 2 | bin 3 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | MiracastSample 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Miracast Sample 2 | 3 | Test application of Android using Presentation class which displays something on the remote display like a TV over Miracast technology. 4 | 5 | ## Demo 6 | ![Demo image](https://lh3.googleusercontent.com/-IWkNvP0iCEw/UNwPCDMGbcI/AAAAAAAAQQM/101yztAhSLg/s1024/IMG_20121227_180023.jpg) 7 | 8 | Install this apk to the Nexus4 and display a simple text "Hello world,…" to the remote display which is connected the Miracast receiver(PTV3000 /firmware 2.2.2). 9 | 10 | ## Digest 11 | 12 | #### How to get displays 13 | 14 | DisplayManger handles all displays including the local display. 15 | 16 | mDisplayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE); 17 | 18 | You can get all displays via DisplayManager. 19 | 20 | Display[] displays = mDisplayManager.getDisplays(); 21 | 22 | 23 | #### Show the remote display 24 | 25 | Super easy to show something on the remote display. Just call show() method which is implemented in Presentation class provided by Android SDKr17. 26 | 27 | private void showPresentation(Display display) { 28 | RemotePresentation presentation = new RemotePresentation(this, display); 29 | presentation.show(); 30 | } 31 | 32 | RemotePresentation class is extended Presentation. 33 | Presentation class looks like Activity. You can set up the display overriding the onCreate method. 34 | 35 | private final class RemotePresentation extends Presentation { 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | setContentView(R.layout.remote_display); 40 | } 41 | } 42 | 43 | This demo apk shows only TextView on the remote display. The layout resource is remote_display.xml. 44 | 45 | 50 | 51 | 59 | 60 | 61 | 62 | 63 | ## How to setup the miracast environment 64 | 65 | #### Test Enviroinment 66 | 67 | ***Nexus4:*** Currently only Nexus4 supports the Miracast(27 Dec. 2012). 68 | 69 | ***PTV3000:*** I've tested this apk with [PTV3000](http://www.netgear.com/home/products/hometheater/media-players/PTV3000.aspx). 70 | 71 | #### Nexus4 72 | 73 | Turn on the "Wireless Display" on the Settings. 74 | 75 | ![Wireless Display](https://lh5.googleusercontent.com/-jsRDm7OwPcA/UNwZf_w53II/AAAAAAAAQSU/gwoLDrnoLi8/s800/device-2012-12-27-184713.png) 76 | 77 | You can find wireless displays and tap an item to connect. 78 | 79 | ![Connecting the wireless display](https://lh6.googleusercontent.com/-dL8nnpfbEts/UNwZf37W6rI/AAAAAAAAQSY/NG9y4QrC36A/s800/device-2012-12-27-184741.png) 80 | 81 | #### PTV3000 82 | 83 | Check the firmware version. I bought this gadget from Amazon.com and the version is 1.0.13. TOO LOW!! This version does not support Miracast. You need to update the firmware in 2 steps. 84 | 85 | ***STEP1:*** Download the latest firmware which is on Internet. I could find the version 2.2.2. This might not be official, I guess. 86 | 87 | ***STEP2:*** Update the firmware. See the [Installation Guide (PDF)](http://www.downloads.netgear.com/files/GDC/PTV3000/PTV3000_IG_10AUG2012.pdf) 88 | 89 | 90 | -------------------------------------------------------------------------------- /ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamrocker/Miracast-Sample/a94ca846f471971be6e6a352734720caf83bc21e/ic_launcher-web.png -------------------------------------------------------------------------------- /libs/android-support-v4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamrocker/Miracast-Sample/a94ca846f471971be6e6a352734720caf83bc21e/libs/android-support-v4.jar -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-17 15 | -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamrocker/Miracast-Sample/a94ca846f471971be6e6a352734720caf83bc21e/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-ldpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamrocker/Miracast-Sample/a94ca846f471971be6e6a352734720caf83bc21e/res/drawable-ldpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamrocker/Miracast-Sample/a94ca846f471971be6e6a352734720caf83bc21e/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adamrocker/Miracast-Sample/a94ca846f471971be6e6a352734720caf83bc21e/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/layout/list_item.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 14 | 22 | 23 | 30 | -------------------------------------------------------------------------------- /res/layout/local_display.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /res/layout/remote_display.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 15 | 16 | -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Miracast Sample 4 | Hello world, Remote Display over Miracast!! 5 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | -------------------------------------------------------------------------------- /src/com/adamrocker/miracastsample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.adamrocker.miracastsample; 2 | 3 | import android.graphics.Point; 4 | import android.hardware.display.DisplayManager; 5 | import android.media.MediaRouter; 6 | import android.os.Bundle; 7 | import android.app.ActionBar; 8 | import android.app.ActionBar.OnNavigationListener; 9 | import android.app.Activity; 10 | import android.app.Presentation; 11 | import android.content.Context; 12 | import android.util.SparseArray; 13 | import android.view.Display; 14 | import android.view.Menu; 15 | import android.view.View; 16 | import android.view.View.OnClickListener; 17 | import android.view.ViewGroup; 18 | import android.widget.ArrayAdapter; 19 | import android.widget.CheckBox; 20 | import android.widget.CompoundButton; 21 | import android.widget.CompoundButton.OnCheckedChangeListener; 22 | import android.widget.ListView; 23 | import android.widget.TextView; 24 | 25 | public class MainActivity extends Activity { 26 | 27 | private DisplayManager mDisplayManager; 28 | private DisplayListAdapter mDisplayListAdapter; 29 | private ListView mListView; 30 | private final SparseArray mActivePresentations = new SparseArray(); 31 | 32 | private final DisplayManager.DisplayListener mDisplayListener = new DisplayManager.DisplayListener() { 33 | @Override 34 | public void onDisplayAdded(int displayId) { 35 | mDisplayListAdapter.updateContents(); 36 | } 37 | 38 | @Override 39 | public void onDisplayChanged(int displayId) { 40 | mDisplayListAdapter.updateContents(); 41 | } 42 | 43 | @Override 44 | public void onDisplayRemoved(int displayId) { 45 | mDisplayListAdapter.updateContents(); 46 | } 47 | }; 48 | 49 | @Override 50 | protected void onCreate(Bundle savedInstanceState) { 51 | super.onCreate(savedInstanceState); 52 | setContentView(R.layout.local_display); 53 | mDisplayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE); 54 | 55 | mDisplayListAdapter = new DisplayListAdapter(this); 56 | mListView = (ListView)findViewById(R.id.display_list); 57 | mListView.setAdapter(mDisplayListAdapter); 58 | } 59 | 60 | protected void onResume() { 61 | super.onResume(); 62 | mDisplayListAdapter.updateContents(); 63 | mDisplayManager.registerDisplayListener(mDisplayListener, null); 64 | } 65 | 66 | private void showPresentation(Display display) { 67 | RemotePresentation presentation = new RemotePresentation(this, display); 68 | mActivePresentations.put(display.getDisplayId(), presentation); 69 | presentation.show(); 70 | } 71 | 72 | private void hidePresentation(Display display) { 73 | final int displayId = display.getDisplayId(); 74 | RemotePresentation presentation = mActivePresentations.get(displayId); 75 | if (presentation == null) { 76 | return; 77 | } 78 | 79 | presentation.dismiss(); 80 | mActivePresentations.delete(displayId); 81 | } 82 | 83 | private final class DisplayListAdapter extends ArrayAdapter { 84 | final Context mContext; 85 | private OnCheckedChangeListener mCheckedRemoteDisplay = new OnCheckedChangeListener() { 86 | @Override 87 | public void onCheckedChanged(CompoundButton view, boolean isChecked) { 88 | synchronized (mCheckedRemoteDisplay) { 89 | final Display display = (Display)view.getTag(); 90 | if (isChecked) { 91 | showPresentation(display); 92 | } else { 93 | hidePresentation(display); 94 | } 95 | } 96 | } 97 | }; 98 | 99 | public DisplayListAdapter(Context context) { 100 | super(context, R.layout.list_item); 101 | mContext = context; 102 | } 103 | 104 | @Override 105 | public View getView(int position, View convertView, ViewGroup parent) { 106 | final View v; 107 | if (convertView == null) { 108 | v = ((Activity) mContext).getLayoutInflater().inflate(R.layout.list_item, null); 109 | } else { 110 | v = convertView; 111 | } 112 | 113 | final Display display = getItem(position); 114 | 115 | //TITLE 116 | TextView tv = (TextView)v.findViewById(R.id.display_id); 117 | tv.setText(display.getName() + "( ID: " + display.getDisplayId() + " )"); 118 | 119 | //DESCRIPTION 120 | tv = (TextView)v.findViewById(R.id.display_desc); 121 | tv.setText(display.toString()); 122 | 123 | //SHOW or HIDE the presentation 124 | CheckBox cb = (CheckBox)v.findViewById(R.id.display_cb); 125 | cb.setTag(display); 126 | cb.setOnCheckedChangeListener(mCheckedRemoteDisplay); 127 | return v; 128 | } 129 | 130 | public void updateContents() { 131 | clear(); 132 | 133 | Display[] displays = mDisplayManager.getDisplays(); 134 | addAll(displays); 135 | } 136 | } 137 | 138 | private final class RemotePresentation extends Presentation { 139 | public RemotePresentation(Context context, Display display) { 140 | super(context, display); 141 | } 142 | 143 | @Override 144 | protected void onCreate(Bundle savedInstanceState) { 145 | super.onCreate(savedInstanceState); 146 | setContentView(R.layout.remote_display); 147 | } 148 | } 149 | } 150 | --------------------------------------------------------------------------------