Untitled
unknown
plain_text
5 months ago
22 kB
4
Indexable
package com.armasight.app.streamUSB; import android.Manifest; import android.app.Activity; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Bitmap; import android.graphics.SurfaceTexture; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.media.projection.MediaProjectionManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Environment; import android.provider.MediaStore; import android.util.Log; import android.view.LayoutInflater; import android.view.Surface; import android.view.View; import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.Fragment; import androidx.lifecycle.Lifecycle; import com.armasight.app.R; import com.armasight.app.base.BaseMainFragment; import com.armasight.app.streamWiFi.ScreenRecordingService; import com.serenegiant.usb.CameraDialog; import com.serenegiant.usb.USBMonitor; import com.serenegiant.usb.UVCCamera; import com.serenegiant.usbcameracommon.UVCCameraHandler; import com.serenegiant.widget.CameraViewInterface; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; public class StreamUSBFragment extends BaseMainFragment implements CameraDialog.CameraDialogParent { public static final String TAG = "StreamUSBFragment"; private static final boolean DEBUG = true; // Request codes and permissions private static final int REQUEST_CAMERA_PERMISSION = 200; private static final int SCREEN_RECORD_REQUEST_CODE = 1001; private static final int PERMISSION_REQUEST_CODE = 1002; // Preview configurations // private static final int PREVIEW_WIDTH = 512; // private static final int PREVIEW_HEIGHT = 384; private static final int PREVIEW_WIDTH = 640; private static final int PREVIEW_HEIGHT = 480; // works private static final int PREVIEW_MODE = 1; private boolean isPreviewRunning = false; // Intent action private static final String ACTION_USB_PERMISSION = "com.armasight.app.USB_PERMISSION"; // UI Elements private ImageButton mCaptureButton; private ImageButton screenRecordButton; private ImageButton screenshotButton; private CameraViewInterface mUVCCameraView; // USB and Camera Handlers private USBMonitor mUSBMonitor; private UVCCameraHandler mCameraHandler; // State variables private boolean isRecording = false; private PendingIntent mPermissionIntent; @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (DEBUG) Log.v(TAG, "onCreate:"); // Request all necessary permissions upfront requestAllPermissions(); // Setup USB permission intent and receiver setupUsbPermissionReceiver(); } private void setupUsbPermissionReceiver() { mPermissionIntent = PendingIntent.getBroadcast( getActivity(), 0, new Intent(ACTION_USB_PERMISSION), PendingIntent.FLAG_IMMUTABLE); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); // Specify the receiver as exported getActivity().registerReceiver(mUsbReceiver, filter, Context.RECEIVER_EXPORTED); } private void requestAllPermissions() { List<String> permissionsToRequest = new ArrayList<>(); if (!hasPermission(Manifest.permission.CAMERA)) { permissionsToRequest.add(Manifest.permission.CAMERA); } if (!hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { permissionsToRequest.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } if (!hasPermission(Manifest.permission.RECORD_AUDIO)) { permissionsToRequest.add(Manifest.permission.RECORD_AUDIO); } if (!permissionsToRequest.isEmpty()) { ActivityCompat.requestPermissions( getActivity(), permissionsToRequest.toArray(new String[0]), PERMISSION_REQUEST_CODE); } } private boolean hasPermission(String permission) { return ContextCompat.checkSelfPermission( getContext(), permission) == PackageManager.PERMISSION_GRANTED; } @Override public View onCreateView( @NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.activity_usb_main, container, false); // Initialize UI elements and handlers initializeUIElements(view); initializeUSBHandlers(); // Handle orientation handleOrientation(getResources().getConfiguration().orientation); return view; } private void initializeUIElements(View view) { mCaptureButton = view.findViewById(R.id.capture_button); mUVCCameraView = view.findViewById(R.id.camera_view); screenRecordButton = view.findViewById(R.id.screen_record_button); screenshotButton = view.findViewById(R.id.screenshot_button); setupCaptureButton(); setupCameraView(); setupScreenRecordButton(); setupScreenshotButton(); } private void setupCaptureButton() { if (mCaptureButton != null) { mCaptureButton.setOnClickListener(mOnClickListener); mCaptureButton.setVisibility(View.INVISIBLE); } } private void setupCameraView() { if (mUVCCameraView != null) { mUVCCameraView.setAspectRatio(PREVIEW_WIDTH / (float) PREVIEW_HEIGHT); mUVCCameraView.setCallback(new CameraViewInterface.Callback() { @Override public void onSurfaceCreated(CameraViewInterface view, Surface surface) { // Start the preview when surface is created if (mCameraHandler != null && !mCameraHandler.isPreviewing()) { mCameraHandler.startPreview(surface); } isPreviewRunning = true; // Set flag to indicate preview is running } @Override public void onSurfaceChanged(CameraViewInterface view, Surface surface, int width, int height) { // Handle surface size changes if necessary } @Override public void onSurfaceDestroy(CameraViewInterface view, Surface surface) { // Stop the preview when the surface is destroyed if (mCameraHandler != null) { mCameraHandler.stopPreview(); } isPreviewRunning = false; // Reset preview running flag } }); } } private void setupScreenRecordButton() { if (screenRecordButton != null) { screenRecordButton.setOnClickListener(v -> { if (isRecording) { stopScreenRecording(); } else { requestScreenRecordingPermissions(); } }); } } private void setupScreenshotButton() { if (screenshotButton != null) { screenshotButton.setOnClickListener(v -> takeScreenshot()); } } private void initializeUSBHandlers() { mUSBMonitor = new USBMonitor(getActivity(), mOnDeviceConnectListener); mCameraHandler = UVCCameraHandler.createHandler( getActivity(), mUVCCameraView, 2, PREVIEW_WIDTH, PREVIEW_HEIGHT, PREVIEW_MODE); requestCameraPermission(); } private void handleOrientation(int orientation) { if (screenshotButton == null || screenRecordButton == null) { Log.e(TAG, "UI elements are null, skipping orientation handling"); return; } if (orientation == Configuration.ORIENTATION_PORTRAIT) { Log.d(TAG, "Switching to portrait mode"); screenshotButton.setVisibility(View.GONE); screenRecordButton.setVisibility(View.GONE); } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) { Log.d(TAG, "Switching to landscape mode"); screenshotButton.setVisibility(View.VISIBLE); screenRecordButton.setVisibility(View.VISIBLE); } } @Override public void onConfigurationChanged(@NonNull Configuration newConfig) { super.onConfigurationChanged(newConfig); // Handle orientation change if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE || newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { // Re-initialize camera view and start preview after orientation change if (mCameraHandler != null && mUVCCameraView != null) { if (mUVCCameraView.getSurfaceTexture() != null) { mCameraHandler.startPreview(new Surface(mUVCCameraView.getSurfaceTexture())); } } handleOrientation(newConfig.orientation); } } private void requestScreenRecordingPermissions() { List<String> permissionsToRequest = new ArrayList<>(); if (!hasPermission(Manifest.permission.RECORD_AUDIO)) { permissionsToRequest.add(Manifest.permission.RECORD_AUDIO); } if (!hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) { permissionsToRequest.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); } if (!permissionsToRequest.isEmpty()) { ActivityCompat.requestPermissions( getActivity(), permissionsToRequest.toArray(new String[0]), PERMISSION_REQUEST_CODE); } else { requestScreenRecording(); } } private void requestScreenRecording() { MediaProjectionManager mediaProjectionManager = (MediaProjectionManager) getActivity().getSystemService(Context.MEDIA_PROJECTION_SERVICE); if (mediaProjectionManager != null) { Intent screenCaptureIntent = mediaProjectionManager.createScreenCaptureIntent(); startActivityForResult(screenCaptureIntent, SCREEN_RECORD_REQUEST_CODE); } } private void stopScreenRecording() { Intent serviceIntent = new Intent(getActivity(), ScreenRecordingService.class); getActivity().stopService(serviceIntent); isRecording = false; updateRecordButton(); } private void startScreenRecordingService(int resultCode, Intent data) { Intent serviceIntent = new Intent(getActivity(), ScreenRecordingService.class); serviceIntent.putExtra("RESULT_CODE", resultCode); serviceIntent.putExtra("DATA", data); ContextCompat.startForegroundService(getActivity(), serviceIntent); isRecording = true; updateRecordButton(); } private void updateRecordButton() { if (isRecording) { screenRecordButton.setImageResource(R.drawable.ic_stop); // Update to stop icon } else { screenRecordButton.setImageResource(R.drawable.ic_record); // Update to record icon } } private void takeScreenshot() { View rootView = getActivity().getWindow().getDecorView().getRootView(); // Hide buttons temporarily toggleButtonsVisibility(View.INVISIBLE); // Capture the screenshot rootView.setDrawingCacheEnabled(true); Bitmap bitmap = Bitmap.createBitmap(rootView.getDrawingCache()); rootView.setDrawingCacheEnabled(false); // Show buttons again toggleButtonsVisibility(View.VISIBLE); saveScreenshot(bitmap); } private void toggleButtonsVisibility(int visibility) { if (screenRecordButton != null) { screenRecordButton.setVisibility(visibility); } if (screenshotButton != null) { screenshotButton.setVisibility(visibility); } } private void saveScreenshot(Bitmap bitmap) { String fileName = "screenshot_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()) + ".png"; OutputStream fos = null; try { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { fos = saveScreenshotToMediaStore(bitmap, fileName); } else { fos = saveScreenshotToFile(bitmap, fileName); } if (fos != null) { bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos); fos.close(); Toast.makeText(getActivity(), "Screenshot saved", Toast.LENGTH_SHORT).show(); } } catch (IOException e) { Log.e(TAG, "Error saving screenshot", e); Toast.makeText(getActivity(), "Error saving screenshot", Toast.LENGTH_SHORT).show(); } } private OutputStream saveScreenshotToMediaStore(Bitmap bitmap, String fileName) throws IOException { ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName); values.put(MediaStore.Images.Media.MIME_TYPE, "image/png"); values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES); Uri uri = getActivity().getContentResolver().insert( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); if (uri == null) { throw new IOException("Failed to create new MediaStore record."); } return getActivity().getContentResolver().openOutputStream(uri); } private OutputStream saveScreenshotToFile(Bitmap bitmap, String fileName) throws IOException { String filePath = Environment.getExternalStorageDirectory() + "/" + Environment.DIRECTORY_PICTURES; File dir = new File(filePath); if (!dir.exists() && !dir.mkdirs()) { throw new IOException("Failed to create directory: " + filePath); } File file = new File(filePath, fileName); return new FileOutputStream(file); } @Override public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { if (requestCode == SCREEN_RECORD_REQUEST_CODE && resultCode == Activity.RESULT_OK && data != null) { startScreenRecordingService(resultCode, data); } else { super.onActivityResult(requestCode, resultCode, data); } } @Override public void onStart() { super.onStart(); if (DEBUG) Log.v(TAG, "onStart:"); // Register USB monitor only if not already registered if (!mUSBMonitor.isRegistered()) { mUSBMonitor.register(); } // Ensure the camera view resumes without reinitializing the preview if (mUVCCameraView != null) mUVCCameraView.onResume(); } @Override public void onStop() { super.onStop(); if (DEBUG) Log.v(TAG, "onStop:"); // Avoid unregistering USB monitor on stop to keep the stream running if (mUVCCameraView != null) mUVCCameraView.onPause(); } // Only fully clean up in onDestroy @Override public void onDestroy() { super.onDestroy(); if (DEBUG) Log.v(TAG, "onDestroy:"); // Release resources only on fragment destruction if (mCameraHandler != null) { mCameraHandler.release(); mCameraHandler = null; } if (mUSBMonitor != null) { mUSBMonitor.unregister(); mUSBMonitor.destroy(); mUSBMonitor = null; } mUVCCameraView = null; mCaptureButton = null; getActivity().unregisterReceiver(mUsbReceiver); // Reset preview state flag isPreviewRunning = false; } private final View.OnClickListener mOnClickListener = view -> { if (view.getId() == R.id.capture_button && mCameraHandler.isOpened()) { if (hasPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) && hasPermission(Manifest.permission.RECORD_AUDIO)) { if (!mCameraHandler.isRecording()) { mCaptureButton.setColorFilter(0xffff0000); mCameraHandler.startRecording(); } else { mCaptureButton.setColorFilter(0); mCameraHandler.stopRecording(); } } } }; private void startPreview() { if (mUVCCameraView != null) { final SurfaceTexture st = mUVCCameraView.getSurfaceTexture(); if (st != null) { mCameraHandler.startPreview(new Surface(st)); getActivity().runOnUiThread(() -> mCaptureButton.setVisibility(View.VISIBLE)); isPreviewRunning = true; } } } private final USBMonitor.OnDeviceConnectListener mOnDeviceConnectListener = new USBMonitor.OnDeviceConnectListener() { @Override public void onAttach(@NonNull final UsbDevice device) { if (DEBUG) Log.v(TAG, "onAttach:"); Toast.makeText(getActivity(), "USB Device Connected", Toast.LENGTH_SHORT).show(); if (mUSBMonitor != null && !mUSBMonitor.hasPermission(device)) { mUSBMonitor.requestPermission(device); } else if (!isPreviewRunning) { // Only start preview if it's not already running mCameraHandler.open(mUSBMonitor.openDevice(device)); startPreview(); isPreviewRunning = true; // Set flag to indicate preview is running } } @Override public void onConnect(@NonNull final UsbDevice device, @NonNull final USBMonitor.UsbControlBlock ctrlBlock, boolean createNew) { if (DEBUG) Log.v(TAG, "onConnect:"); if (!isPreviewRunning) { // Check if preview is already running mCameraHandler.open(ctrlBlock); startPreview(); isPreviewRunning = true; } } @Override public void onDisconnect(@NonNull final UsbDevice device, @NonNull final USBMonitor.UsbControlBlock ctrlBlock) { if (DEBUG) Log.v(TAG, "onDisconnect:"); if (mCameraHandler != null) { mCameraHandler.close(); } } @Override public void onDettach(@NonNull final UsbDevice device) { if (DEBUG) Log.v(TAG, "onDettach:"); if (mCameraHandler.isOpened()) { mCameraHandler.close(); } Toast.makeText(getActivity(), "USB Device Detached", Toast.LENGTH_SHORT).show(); } @Override public void onCancel(@NonNull final UsbDevice device) { if (DEBUG) Log.v(TAG, "onCancel:"); } }; private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (ACTION_USB_PERMISSION.equals(intent.getAction())) { synchronized (this) { UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { if (device != null) { Toast.makeText(getActivity(), "Permission granted for device: " + device.getDeviceName(), Toast.LENGTH_SHORT).show(); // Automatically start preview when permission is granted mCameraHandler.open(mUSBMonitor.openDevice(device)); startPreview(); } } else { if (device != null) { Toast.makeText(getActivity(), "Permission denied for device: " + device.getDeviceName(), Toast.LENGTH_SHORT).show(); } } } } } }; private void requestCameraPermission() { if (!hasPermission(Manifest.permission.CAMERA)) { ActivityCompat.requestPermissions( getActivity(), new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION); } } @Override public void onDialogResult(boolean canceled) { if (DEBUG) Log.v(TAG, "onDialogResult:canceled=" + canceled); } @Override public USBMonitor getUSBMonitor() { return mUSBMonitor; } @Override public void onRequestPermissionsResult( int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == PERMISSION_REQUEST_CODE) { if (allPermissionsGranted(grantResults)) { requestScreenRecording(); } else { Toast.makeText(getActivity(), "Permissions denied", Toast.LENGTH_SHORT).show(); } } } private boolean allPermissionsGranted(int[] grantResults) { for (int grantResult : grantResults) { if (grantResult != PackageManager.PERMISSION_GRANTED) { return false; } } return true; } }
Editor is loading...
Leave a Comment