1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.android.apis.media.projection;
18 
19 import com.example.android.apis.R;
20 
21 import android.app.Activity;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.res.Configuration;
25 import android.hardware.display.DisplayManager;
26 import android.hardware.display.VirtualDisplay;
27 import android.media.projection.MediaProjection;
28 import android.media.projection.MediaProjectionManager;
29 import android.os.Bundle;
30 import android.util.DisplayMetrics;
31 import android.util.Log;
32 import android.view.Surface;
33 import android.view.SurfaceHolder;
34 import android.view.SurfaceView;
35 import android.view.View;
36 import android.view.ViewGroup;
37 import android.widget.AdapterView;
38 import android.widget.ArrayAdapter;
39 import android.widget.Spinner;
40 import android.widget.Toast;
41 import android.widget.ToggleButton;
42 
43 import java.util.Arrays;
44 import java.util.List;
45 
46 public class MediaProjectionDemo extends Activity {
47     private static final String TAG = "MediaProjectionDemo";
48     private static final int PERMISSION_CODE = 1;
49     private static final List<Resolution> RESOLUTIONS = Arrays.asList(
50             new Resolution(640,360),
51             new Resolution(960,540),
52             new Resolution(1366,768),
53             new Resolution(1600,900));
54 
55     private int mScreenDensity;
56     private MediaProjectionManager mProjectionManager;
57 
58     private int mDisplayWidth;
59     private int mDisplayHeight;
60     private boolean mScreenSharing;
61 
62     private MediaProjection mMediaProjection;
63     private VirtualDisplay mVirtualDisplay;
64     private Surface mSurface;
65     private SurfaceView mSurfaceView;
66     private ToggleButton mToggle;
67 
68     @Override
onCreate(Bundle savedInstanceState)69     public void onCreate(Bundle savedInstanceState) {
70         super.onCreate(savedInstanceState);
71         setContentView(R.layout.media_projection);
72 
73         DisplayMetrics metrics = new DisplayMetrics();
74         getWindowManager().getDefaultDisplay().getMetrics(metrics);
75         mScreenDensity = metrics.densityDpi;
76 
77         mSurfaceView = (SurfaceView) findViewById(R.id.surface);
78         mSurface = mSurfaceView.getHolder().getSurface();
79         mProjectionManager =
80             (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
81 
82         ArrayAdapter<Resolution> arrayAdapter = new ArrayAdapter<Resolution>(
83                 this, android.R.layout.simple_list_item_1, RESOLUTIONS);
84         Spinner s = (Spinner) findViewById(R.id.spinner);
85         s.setAdapter(arrayAdapter);
86         s.setOnItemSelectedListener(new ResolutionSelector());
87         s.setSelection(0);
88 
89         mToggle = (ToggleButton) findViewById(R.id.screen_sharing_toggle);
90         mToggle.setSaveEnabled(false);
91     }
92 
93     @Override
onStop()94     protected void onStop() {
95         stopScreenSharing();
96         super.onStop();
97     }
98 
99     @Override
onDestroy()100     public void onDestroy() {
101         super.onDestroy();
102         if (mMediaProjection != null) {
103             mMediaProjection.stop();
104             mMediaProjection = null;
105         }
106     }
107 
108     @Override
onActivityResult(int requestCode, int resultCode, Intent data)109     public void onActivityResult(int requestCode, int resultCode, Intent data) {
110         if (requestCode != PERMISSION_CODE) {
111             Log.e(TAG, "Unknown request code: " + requestCode);
112             return;
113         }
114         if (resultCode != RESULT_OK) {
115             Toast.makeText(this,
116                     "User denied screen sharing permission", Toast.LENGTH_SHORT).show();
117             return;
118         }
119         mMediaProjection = mProjectionManager.getMediaProjection(resultCode, data);
120         mMediaProjection.registerCallback(new MediaProjectionCallback(), null);
121         mVirtualDisplay = createVirtualDisplay();
122     }
123 
onToggleScreenShare(View view)124     public void onToggleScreenShare(View view) {
125         if (((ToggleButton) view).isChecked()) {
126             shareScreen();
127         } else {
128             stopScreenSharing();
129         }
130     }
131 
shareScreen()132     private void shareScreen() {
133         mScreenSharing = true;
134         if (mSurface == null) {
135             return;
136         }
137         if (mMediaProjection == null) {
138             startActivityForResult(mProjectionManager.createScreenCaptureIntent(),
139                     PERMISSION_CODE);
140             return;
141         }
142         mVirtualDisplay = createVirtualDisplay();
143     }
144 
stopScreenSharing()145     private void stopScreenSharing() {
146         if (mToggle.isChecked()) {
147             mToggle.setChecked(false);
148         }
149 
150         mScreenSharing = false;
151         if (mVirtualDisplay != null) {
152             mVirtualDisplay.release();
153             mVirtualDisplay = null;
154         }
155     }
156 
createVirtualDisplay()157     private VirtualDisplay createVirtualDisplay() {
158         return mMediaProjection.createVirtualDisplay("ScreenSharingDemo",
159                 mDisplayWidth, mDisplayHeight, mScreenDensity,
160                 DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
161                 mSurface, null /*Callbacks*/, null /*Handler*/);
162     }
163 
resizeVirtualDisplay()164     private void resizeVirtualDisplay() {
165         if (mVirtualDisplay == null) {
166             return;
167         }
168         mVirtualDisplay.resize(mDisplayWidth, mDisplayHeight, mScreenDensity);
169     }
170 
171     private class ResolutionSelector implements Spinner.OnItemSelectedListener {
172         @Override
onItemSelected(AdapterView<?> parent, View v, int pos, long id)173         public void onItemSelected(AdapterView<?> parent, View v, int pos, long id) {
174             Resolution r = (Resolution) parent.getItemAtPosition(pos);
175             ViewGroup.LayoutParams lp = mSurfaceView.getLayoutParams();
176             if (getResources().getConfiguration().orientation
177                     == Configuration.ORIENTATION_LANDSCAPE) {
178                 mDisplayHeight = r.y;
179                 mDisplayWidth = r.x;
180             } else {
181                 mDisplayHeight = r.x;
182                 mDisplayWidth = r.y;
183             }
184             lp.height = mDisplayHeight;
185             lp.width = mDisplayWidth;
186             mSurfaceView.setLayoutParams(lp);
187         }
188 
189         @Override
onNothingSelected(AdapterView<?> parent)190         public void onNothingSelected(AdapterView<?> parent) { /* Ignore */ }
191     }
192 
193     private class MediaProjectionCallback extends MediaProjection.Callback {
194         @Override
onStop()195         public void onStop() {
196             mMediaProjection = null;
197             stopScreenSharing();
198         }
199     }
200 
201     private class SurfaceCallbacks implements SurfaceHolder.Callback {
202         @Override
surfaceChanged(SurfaceHolder holder, int format, int width, int height)203         public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
204             mDisplayWidth = width;
205             mDisplayHeight = height;
206             resizeVirtualDisplay();
207         }
208 
209         @Override
surfaceCreated(SurfaceHolder holder)210         public void surfaceCreated(SurfaceHolder holder) {
211             mSurface = holder.getSurface();
212             if (mScreenSharing) {
213                 shareScreen();
214             }
215         }
216 
217         @Override
surfaceDestroyed(SurfaceHolder holder)218         public void surfaceDestroyed(SurfaceHolder holder) {
219             if (!mScreenSharing) {
220                 stopScreenSharing();
221             }
222         }
223     }
224 
225     private static class Resolution {
226         int x;
227         int y;
228 
Resolution(int x, int y)229         public Resolution(int x, int y) {
230             this.x = x;
231             this.y = y;
232         }
233 
234         @Override
toString()235         public String toString() {
236             return x + "x" + y;
237         }
238     }
239 }
240