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 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 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 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 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 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 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 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 141 public void onPause() { 142 super.onPause(); 143 stopScreenCapture(); 144 } 145 146 @Override 147 public void onDestroy() { 148 super.onDestroy(); 149 tearDownMediaProjection(); 150 } 151 152 private void setUpMediaProjection() { 153 mMediaProjection = mMediaProjectionManager.getMediaProjection(mResultCode, mResultData); 154 } 155 156 private void tearDownMediaProjection() { 157 if (mMediaProjection != null) { 158 mMediaProjection.stop(); 159 mMediaProjection = null; 160 } 161 } 162 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 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 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