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