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.screencapture;
18 
19 import android.app.Activity;
20 import android.content.Context;
21 import android.content.Intent;
22 import android.hardware.display.DisplayManager;
23 import android.hardware.display.VirtualDisplay;
24 import android.media.projection.MediaProjection;
25 import android.media.projection.MediaProjectionManager;
26 import android.os.Bundle;
27 import android.support.annotation.Nullable;
28 import android.support.v4.app.Fragment;
29 import android.util.DisplayMetrics;
30 import android.view.LayoutInflater;
31 import android.view.Surface;
32 import android.view.SurfaceView;
33 import android.view.View;
34 import android.view.ViewGroup;
35 import android.widget.Button;
36 import android.widget.Toast;
37 
38 import com.example.android.common.logger.Log;
39 
40 /**
41  * Provides UI for the screen capture.
42  */
43 public class ScreenCaptureFragment extends Fragment implements View.OnClickListener {
44 
45     private static final String TAG = "ScreenCaptureFragment";
46 
47     private static final String STATE_RESULT_CODE = "result_code";
48     private static final String STATE_RESULT_DATA = "result_data";
49 
50     private static final int REQUEST_MEDIA_PROJECTION = 1;
51 
52     private int mScreenDensity;
53 
54     private int mResultCode;
55     private Intent mResultData;
56 
57     private Surface mSurface;
58     private MediaProjection mMediaProjection;
59     private VirtualDisplay mVirtualDisplay;
60     private MediaProjectionManager mMediaProjectionManager;
61     private Button mButtonToggle;
62     private SurfaceView mSurfaceView;
63 
64     @Override
onCreate(Bundle savedInstanceState)65     public void onCreate(Bundle savedInstanceState) {
66         super.onCreate(savedInstanceState);
67         if (savedInstanceState != null) {
68             mResultCode = savedInstanceState.getInt(STATE_RESULT_CODE);
69             mResultData = savedInstanceState.getParcelable(STATE_RESULT_DATA);
70         }
71     }
72 
73     @Nullable
74     @Override
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)75     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
76         return inflater.inflate(R.layout.fragment_screen_capture, container, false);
77     }
78 
79     @Override
onViewCreated(View view, Bundle savedInstanceState)80     public void onViewCreated(View view, Bundle savedInstanceState) {
81         mSurfaceView = (SurfaceView) view.findViewById(R.id.surface);
82         mSurface = mSurfaceView.getHolder().getSurface();
83         mButtonToggle = (Button) view.findViewById(R.id.toggle);
84         mButtonToggle.setOnClickListener(this);
85     }
86 
87     @Override
onActivityCreated(Bundle savedInstanceState)88     public void onActivityCreated(Bundle savedInstanceState) {
89         super.onActivityCreated(savedInstanceState);
90         Activity activity = getActivity();
91         DisplayMetrics metrics = new DisplayMetrics();
92         activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
93         mScreenDensity = metrics.densityDpi;
94         mMediaProjectionManager = (MediaProjectionManager)
95                 activity.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
96     }
97 
98     @Override
onSaveInstanceState(Bundle outState)99     public void onSaveInstanceState(Bundle outState) {
100         super.onSaveInstanceState(outState);
101         if (mResultData != null) {
102             outState.putInt(STATE_RESULT_CODE, mResultCode);
103             outState.putParcelable(STATE_RESULT_DATA, mResultData);
104         }
105     }
106 
107     @Override
onClick(View v)108     public void onClick(View v) {
109         switch (v.getId()) {
110             case R.id.toggle:
111                 if (mVirtualDisplay == null) {
112                     startScreenCapture();
113                 } else {
114                     stopScreenCapture();
115                 }
116                 break;
117         }
118     }
119 
120     @Override
onActivityResult(int requestCode, int resultCode, Intent data)121     public void onActivityResult(int requestCode, int resultCode, Intent data) {
122         if (requestCode == REQUEST_MEDIA_PROJECTION) {
123             if (resultCode != Activity.RESULT_OK) {
124                 Log.i(TAG, "User cancelled");
125                 Toast.makeText(getActivity(), R.string.user_cancelled, Toast.LENGTH_SHORT).show();
126                 return;
127             }
128             Activity activity = getActivity();
129             if (activity == null) {
130                 return;
131             }
132             Log.i(TAG, "Starting screen capture");
133             mResultCode = resultCode;
134             mResultData = data;
135             setUpMediaProjection();
136             setUpVirtualDisplay();
137         }
138     }
139 
140     @Override
onPause()141     public void onPause() {
142         super.onPause();
143         stopScreenCapture();
144     }
145 
146     @Override
onDestroy()147     public void onDestroy() {
148         super.onDestroy();
149         tearDownMediaProjection();
150     }
151 
setUpMediaProjection()152     private void setUpMediaProjection() {
153         mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCode, mResultData);
154     }
155 
tearDownMediaProjection()156     private void tearDownMediaProjection() {
157         if (mMediaProjection != null) {
158             mMediaProjection.stop();
159             mMediaProjection = null;
160         }
161     }
162 
startScreenCapture()163     private void startScreenCapture() {
164         Activity activity = getActivity();
165         if (mSurface == null || activity == null) {
166             return;
167         }
168         if (mMediaProjection != null) {
169             setUpVirtualDisplay();
170         } else if (mResultCode != 0 && mResultData != null) {
171             setUpMediaProjection();
172             setUpVirtualDisplay();
173         } else {
174             Log.i(TAG, "Requesting confirmation");
175             // This initiates a prompt dialog for the user to confirm screen projection.
176             startActivityForResult(
177                     mMediaProjectionManager.createScreenCaptureIntent(),
178                     REQUEST_MEDIA_PROJECTION);
179         }
180     }
181 
setUpVirtualDisplay()182     private void setUpVirtualDisplay() {
183         Log.i(TAG, "Setting up a VirtualDisplay: " +
184                 mSurfaceView.getWidth() + "x" + mSurfaceView.getHeight() +
185                 " (" + mScreenDensity + ")");
186         mVirtualDisplay = mMediaProjection.createVirtualDisplay("ScreenCapture",
187                 mSurfaceView.getWidth(), mSurfaceView.getHeight(), mScreenDensity,
188                 DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
189                 mSurface, null, null);
190         mButtonToggle.setText(R.string.stop);
191     }
192 
stopScreenCapture()193     private void stopScreenCapture() {
194         if (mVirtualDisplay == null) {
195             return;
196         }
197         mVirtualDisplay.release();
198         mVirtualDisplay = null;
199         mButtonToggle.setText(R.string.start);
200     }
201 
202 }
203