Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 1 | page.title=Picture-in-picture |
| 2 | page.keywords=preview,sdk,PIP,Picture-in-picture |
| 3 | page.tags=androidn |
| 4 | |
| 5 | @jd:body |
| 6 | |
Joe Fernandez | 98b0ec6 | 2016-03-08 22:32:51 -0800 | [diff] [blame] | 7 | <div id="qv-wrapper"> |
| 8 | <div id="qv"> |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 9 | |
| 10 | <h2>In this document</h2> |
| 11 | <ol> |
| 12 | <li><a href="#declaring">Declaring Your Activity Supports |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 13 | Picture-in-picture</a></li> |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 14 | <li><a href="#pip_button">Switching Your Activity to Picture-in-picture</a> |
| 15 | </li> |
| 16 | <li><a href="#handling_ui">Handling UI During Picture-in-picture</a> |
| 17 | </li> |
| 18 | <li><a href="#continuing_playback">Continuing Video Playback While in |
| 19 | Picture-in-picture</a></li> |
Daniel Yu | c5d9c8f | 2016-03-21 16:41:26 -0700 | [diff] [blame] | 20 | <li><a href="#single_playback">Using a Single Playback Activity for |
| 21 | Picture-in-picture</a></li> |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 22 | <li><a href="#best">Best Practices</a></li> |
| 23 | </ol> |
| 24 | |
| 25 | <h2>See Also</h2> |
| 26 | <ol> |
| 27 | <li><a href="{@docRoot}preview/features/multi-window.html">Multi-Window |
| 28 | Support</a></li> |
| 29 | </ol> |
| 30 | |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 31 | </div> |
| 32 | </div> |
| 33 | |
David Friedman | fffa8ac | 2016-03-07 22:13:29 -0800 | [diff] [blame] | 34 | <p>In Android N, Android TV users can now watch a video |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 35 | in a pinned window in a corner of the screen when navigating within |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 36 | apps. Picture-in-picture (PIP) mode lets apps run a video |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 37 | activity in the pinned window while another activity continues in the |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 38 | background. The PIP window lets users multitask while using your app, which |
| 39 | helps users be more productive.</p> |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 40 | |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 41 | <p>Your app can decide when to trigger PIP mode. Here are some examples of |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 42 | when to enter PIP mode:</p> |
| 43 | |
| 44 | <ul> |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 45 | <li>Your app can move a video into PIP mode when the user navigates |
| 46 | back from the video to browse other content.</li> |
| 47 | <li>Your app can switch a video into PIP mode while a user watches the end |
| 48 | of an episode of content. The main screen displays promotional or summary |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 49 | information about the next episode in the series.</li> |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 50 | <li>Your app can provide a way for users to queue up additional content while |
| 51 | they watch a video. The video continues playing in PIP mode while the main |
| 52 | screen displays a content selection activity.</li> |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 53 | </ul> |
| 54 | |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 55 | <p>The PIP window is 240x135 dp and is shown at the top-most layer in one of |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 56 | the four corners of the screen, chosen by the system. The user can bring up a |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 57 | PIP menu that lets them toggle the PIP window to full-screen, or close the PIP |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 58 | window, by holding down the <b>Home</b> button on the remote. If another |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 59 | video starts playing on the main screen, the PIP window is automatically |
| 60 | closed. Users can also close the PIP window through Recents.</p> |
| 61 | |
| 62 | <img src="{@docRoot}preview/images/pip-active.png" /> |
| 63 | <p class="img-caption"><strong>Figure 1.</strong> A Picture-in-picture |
| 64 | video visible in a corner of the screen while the user browses content |
| 65 | on the main screen.</p> |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 66 | |
David Friedman | fffa8ac | 2016-03-07 22:13:29 -0800 | [diff] [blame] | 67 | <p>PIP leverages the multi-window APIs available in Android N to |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 68 | provide the pinned video overlay window. To add PIP to your app, you need to |
| 69 | register your activities that support PIP, switch your activity to PIP mode as |
| 70 | needed, and make sure UI elements are hidden and video playback continues when |
| 71 | the activity is in PIP mode.</p> |
| 72 | |
| 73 | <h2 id="declaring">Declaring Your Activity Supports Picture-in-picture</h2> |
| 74 | |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 75 | <p>By default, the system does not automatically support PIP for apps. |
| 76 | If you want support PIP in your app, register your video |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 77 | activity in your manifest by setting |
| 78 | <code>android:supportsPictureInPicture</code> and |
| 79 | <code>android:resizeableActivity</code> to <code>true</code>. Also, specify |
| 80 | that your activity handles layout configuration changes so that your activity |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 81 | doesn't relaunch when layout changes occur during PIP mode transitions.</p> |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 82 | |
| 83 | <pre> |
| 84 | <activity android:name="VideoActivity" |
| 85 | android:resizeableActivity="true" |
| 86 | android:supportsPictureInPicture="true" |
| 87 | android:configChanges= |
| 88 | "screenSize|smallestScreenSize|screenLayout|orientation" |
| 89 | ... |
| 90 | </pre> |
| 91 | |
| 92 | <p>When registering your activity, keep in mind that in PIP mode, your |
| 93 | activity is shown in a small overlay window on a TV screen. Video playback |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 94 | activities with minimal UI provide the best user experience. Activities that |
| 95 | contain small UI elements might not provide a good user experience |
| 96 | when switched to PIP mode, because users can't see details of the UI elements |
| 97 | in the PIP window.</p> |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 98 | |
| 99 | <h2 id="pip_button">Switching Your Activity to Picture-in-picture</h2> |
| 100 | |
| 101 | When you need to switch your activity into PIP mode, call |
Daniel Yu | 82f8756 | 2016-04-05 13:46:49 -0700 | [diff] [blame] | 102 | <code>Activity.enterPictureInPictureMode()</code>. The following example |
| 103 | switches to PIP mode when the user selects a dedicated PIP button on a media |
| 104 | control bar:</p> |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 105 | |
| 106 | <pre> |
| 107 | @Override |
| 108 | public void onActionClicked(Action action) { |
| 109 | if (action.getId() == R.id.lb_control_picture_in_picture) { |
Daniel Yu | 82f8756 | 2016-04-05 13:46:49 -0700 | [diff] [blame] | 110 | getActivity().enterPictureInPictureMode(); |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 111 | return; |
| 112 | } |
| 113 | ... |
| 114 | </pre> |
| 115 | |
| 116 | <p>Adding a PIP button to your media control bar lets your user easily switch |
| 117 | to PIP mode while controlling video playback.</p> |
| 118 | |
| 119 | <img src="{@docRoot}preview/images/pip-button.png" /> |
| 120 | <p class="img-caption"><strong>Figure 1.</strong> A Picture-in-picture |
| 121 | button on a media control bar.</p> |
| 122 | |
David Friedman | fffa8ac | 2016-03-07 22:13:29 -0800 | [diff] [blame] | 123 | <p>Android N includes a new |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 124 | <code>PlaybackControlsRow.PictureInPictureAction</code> class which defines |
| 125 | control bar PIP actions and uses the PIP icon.</p> |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 126 | |
| 127 | <h2 id="handling_ui">Handling UI During Picture-in-picture</h2> |
| 128 | |
| 129 | <p>When your activity enters PIP mode, your activity should only show video |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 130 | playback. Remove UI elements before your activity enters PIP, |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 131 | and restore these elements when your activity becomes full-screen again. |
Daniel Yu | 82f8756 | 2016-04-05 13:46:49 -0700 | [diff] [blame] | 132 | Override <code>Activity.onPictureInPictureModeChanged()</code> or |
| 133 | <code>Fragment.onPictureInPictureModeChanged()</code> and enable or |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 134 | disable your UI elements as needed, for example:</p> |
| 135 | |
| 136 | <pre> |
| 137 | @Override |
Daniel Yu | 82f8756 | 2016-04-05 13:46:49 -0700 | [diff] [blame] | 138 | public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) { |
| 139 | if (isInPictureInPictureMode) { |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 140 | // Hide the controls in picture-in-picture mode. |
| 141 | ... |
| 142 | } else { |
| 143 | // Restore the playback UI based on the playback status. |
| 144 | ... |
| 145 | } |
| 146 | } |
| 147 | </pre> |
| 148 | |
| 149 | <h2 id="continuing_playback">Continuing Video Playback While in |
| 150 | Picture-in-picture</h2> |
| 151 | |
| 152 | <p>When your activity switches to PIP, the system considers the activity in a |
| 153 | paused state, and calls your activity's <code>onPause()</code> method. Video |
| 154 | playback should not be paused and should continue playing if the activity is |
| 155 | paused due to PIP mode. Check for PIP in your activity's |
| 156 | <code>onPause()</code> method and handle playback appropriately, for |
| 157 | example:</p> |
| 158 | |
| 159 | <pre> |
| 160 | @Override |
| 161 | public void onPause() { |
Daniel Yu | 82f8756 | 2016-04-05 13:46:49 -0700 | [diff] [blame] | 162 | // If called while in PIP mode, do not pause playback |
| 163 | if (isInPictureInPictureMode()) { |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 164 | // Continue playback |
| 165 | ... |
| 166 | } |
| 167 | // If paused but not in PIP, pause playback if necessary |
| 168 | ... |
| 169 | } |
| 170 | </pre> |
| 171 | |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 172 | <p>When your activity switches out of PIP mode back to full-screen mode, the |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 173 | system resumes your activity and calls your <code>onResume()</code> method.</p> |
| 174 | |
Daniel Yu | c5d9c8f | 2016-03-21 16:41:26 -0700 | [diff] [blame] | 175 | <h2 id="single_playback">Using a Single Playback Activity for |
| 176 | Picture-in-picture</h2> |
| 177 | |
| 178 | <p>In your app, a user might select a new video when browsing for content on |
| 179 | the main screen, while a video playback activity is in PIP mode. Play the new |
| 180 | video in the existing playback activity in full screen mode, instead of |
| 181 | launching a new activity that might confuse the user.</p> |
| 182 | |
| 183 | <p>To ensure a single activity is used for video playback requests and |
| 184 | switched into or out of PIP mode as needed, set the activity's |
| 185 | <code>android:launchMode</code> to <code>singleTask</code> in your manifest: |
| 186 | </p> |
| 187 | |
| 188 | <pre> |
| 189 | <activity android:name="VideoActivity" |
| 190 | ... |
| 191 | android:supportsPictureInPicture="true" |
| 192 | android:launchMode="singleTask" |
| 193 | ... |
| 194 | </pre> |
| 195 | |
| 196 | <p>In your activity, override {@link android.app.Activity#onNewIntent |
| 197 | Activity.onNewIntent()} and handle the new video, stopping any existing video |
| 198 | playback if needed.</p> |
| 199 | |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 200 | <h2 id="best">Best Practices</h2> |
| 201 | |
| 202 | <p>PIP is intended for activities that play full-screen video. When switching |
| 203 | your activity into PIP mode, avoid showing anything except video content. |
| 204 | Track when your activity enters PIP mode and hide UI elements, as described |
Daniel Yu | d78890f | 2016-03-04 11:16:46 -0800 | [diff] [blame] | 205 | in <a href="#handling_ui">Handling UI During Picture-in-picture</a>.</p> |
Daniel Yu | 192d56d | 2016-02-23 16:43:04 -0800 | [diff] [blame] | 206 | |
| 207 | <p>Since the PIP window is shown as a floating window in the corner of the |
| 208 | screen, you should avoid showing critical information in the main screen |
| 209 | in any area that can be obscured by the PIP window.</p> |
| 210 | |
| 211 | <p>When an activity is in PIP mode, by default it doesn't get input focus. To |
| 212 | receive input events while in PIP mode, use |
| 213 | <code>MediaSession.setMediaButtonReceiver()</code>.</p> |