Untitled
unknown
plain_text
a year ago
22 kB
6
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