Skip to main content

Android System


📸 Camera Usage Method​

Accessing the camera can typically be achieved through the Camera2 API or the legacy Camera API. The following is a basic code example using the Camera2 API to access the camera:


1. Add Permissions​

Add the required permissions in AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />

2. Check Camera Permissions​

After installing the App, you can enter system settings to grant the App's camera access permission by default, avoiding prompts needed during use.


3. Create Camera2 API Configuration​

First, you need to obtain the device's camera information and open the camera:

public class CameraActivity extends AppCompatActivity {
private CameraDevice mCameraDevice;
private CameraCaptureSession mCaptureSession;
private CameraCharacteristics mCameraCharacteristics;
private String mCameraId;
private static final int REQUEST_CAMERA_PERMISSION = 200;
private CameraManager mCameraManager;
// Change SurfaceView to TextureView if needed
private TextureView mSurfaceView;
private Surface mSurface;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);

mSurfaceView = findViewById(R.id.surfaceView);
mCameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);

try {
// Get the camera IDs supported by the device
for (String cameraId : mCameraManager.getCameraIdList()) {
mCameraCharacteristics = mCameraManager.getCameraCharacteristics(cameraId);
Integer facing = mCameraCharacteristics.get(CameraCharacteristics.LENS_FACING);
// Use front camera by default, choose camera based on actual needs
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
mCameraId = cameraId;
break;
}
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
openCamera();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, REQUEST_CAMERA_PERMISSION);
}
}

@RequiresPermission(Manifest.permission.CAMERA)
private void openCamera() {
try {
mCameraManager.openCamera(mCameraId, new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice camera) {
mCameraDevice = camera;
createCameraPreviewSession();
}

@Override
public void onDisconnected(@NonNull CameraDevice camera) {
camera.close();
}

@Override
public void onError(@NonNull CameraDevice camera, int error) {
camera.close();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}

private void createCameraPreviewSession() {
try {
SurfaceTexture surfaceTexture = mSurfaceView.getSurfaceTexture();
surfaceTexture.setDefaultBufferSize(1920, 1080);
mSurface = new Surface(surfaceTexture);

// Configure preview request
CaptureRequest.Builder previewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
previewRequestBuilder.addTarget(mSurface);

mCameraDevice.createCaptureSession(Arrays.asList(mSurface), new CameraCaptureSession.StateCallback() {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
if (mCameraDevice == null) return;
mCaptureSession = session;
try {
// Start displaying preview
mCaptureSession.setRepeatingRequest(previewRequestBuilder.build(), null, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}

@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Toast.makeText(CameraActivity.this, "Configuration failed", Toast.LENGTH_SHORT).show();
}
}, null);
} catch (CameraAccessException e) {
e.printStackTrace();
}
}

@Override
protected void onPause() {
super.onPause();
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
}
}

4. Layout File​

Add a SurfaceView in activity_camera.xml to display the camera preview:

<TextureView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

5. Close Camera When Finished​

Close the camera device in the onPause() method:

@Override
protected void onPause() {
super.onPause();
if (mCameraDevice != null) {
mCameraDevice.close();
mCameraDevice = null;
}
}

🎙 Microphone Usage Method​

Using the microphone for audio capture can typically be achieved through MediaRecorder or AudioRecord. MediaRecorder is more suitable for audio recording, while AudioRecord provides lower-level control, suitable for scenarios requiring fine-grained control over audio capture.


Method 1: Simple Audio Recording Using MediaRecorder​

MediaRecorder is a high-level interface, suitable for audio recording operations, simple and easy to use.


Step 1: Add Permissions

Add recording permissions in the AndroidManifest.xml file:

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.microphone" />

Step 2: Initialize MediaRecorder

Create and configure MediaRecorder in the code:

public class AudioRecorderActivity extends AppCompatActivity {
private MediaRecorder mediaRecorder;
private String audioFilePath;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_audio_recorder);
// Declare button variables
Button startButton = findViewById(R.id.startButton);
Button stopButton = findViewById(R.id.stopButton);
// Set audio save path
audioFilePath = getExternalFilesDir(null).getAbsolutePath() + "/audio_record.aac";
// Initialize MediaRecorder
mediaRecorder = new MediaRecorder();
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // Use microphone as audio source
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); // Set audio file format
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // Set audio encoding method
mediaRecorder.setOutputFile(audioFilePath); // Set output file path
// Step 2: Set click event for start recording button
startButton.setOnClickListener(v -> {
// Call method to start recording
Log.i("wtf","startRecording");
startRecording();
});

// Step 3: Set click event for stop recording button
stopButton.setOnClickListener(v -> {
// Call method to stop recording
Log.i("wtf","stopRecording");
stopRecording();
});
}
// Start recording
public void startRecording() {
try {
mediaRecorder.prepare(); // Prepare recording
mediaRecorder.start(); // Start recording
} catch (IOException e) {
System.out.print("Startup exception");
e.printStackTrace();
}
}

// Stop recording
public void stopRecording() {
try {
mediaRecorder.stop(); // Stop recording
mediaRecorder.release(); // Release resources
} catch (RuntimeException e) {
e.printStackTrace();
}
}

@Override
protected void onDestroy() {
super.onDestroy();
if (mediaRecorder != null) {
mediaRecorder.release(); // Ensure resource release
}
}
}

Step 3: Start and Stop Recording

You can control the start and stop of recording through buttons or other controls, for example:

Button startButton = findViewById(R.id.startButton);
Button stopButton = findViewById(R.id.stopButton);

startButton.setOnClickListener(v -> startRecording());
stopButton.setOnClickListener(v -> stopRecording());

Method 2: Low-Latency Audio Recording Using AudioRecord​

If you need more precise audio control, AudioRecord is a lower-level interface suitable for real-time audio processing.

Step 1: Add Permissions

Also need to add recording permissions in the AndroidManifest.xml file:

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature android:name="android.hardware.microphone" />

Step 2: Initialize AudioRecord

public class AudioRecorderActivity extends AppCompatActivity {
private static final int SAMPLE_RATE_IN_HZ = 44100; // Sample rate
private AudioRecord audioRecord;
private boolean isRecording = false;
private Thread recordingThread;
private String audioFilePath;
private FileOutputStream fileOutputStream; // File output stream

@Override
@RequiresPermission(Manifest.permission.RECORD_AUDIO)
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_audio_recorder);
// Declare button variables
Button startButton = findViewById(R.id.startButton);
Button stopButton = findViewById(R.id.stopButton);
// AudioRecord initialization
int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE_IN_HZ, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);

audioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
SAMPLE_RATE_IN_HZ,
AudioFormat.CHANNEL_IN_MONO,
AudioFormat.ENCODING_PCM_16BIT,
bufferSize);

// Audio recording thread
recordingThread = new Thread(new Runnable() {
@Override
public void run() {
recordAudio();
}
});

startButton.setOnClickListener(v -> {
// Call method to start recording
Log.i("wtf","startRecording");
startRecording();
});

// Step 3: Set click event for stop recording button
stopButton.setOnClickListener(v -> {
// Call method to stop recording
Log.i("wtf","stopRecording");
stopRecording();
});
}

// Start recording
public void startRecording() {
audioRecord.startRecording();
isRecording = true;
recordingThread.start();
}

// Stop recording
public void stopRecording() {
isRecording = false;
audioRecord.stop();
audioRecord.release();
}

private void recordAudio() {
// Create audio file path (in private directory of external storage)
String audioFileName = "audio_record_" + System.currentTimeMillis() + ".wav";
File audioFile = new File(getExternalFilesDir(null), audioFileName);
audioFilePath = audioFile.getAbsolutePath(); // Save file path to member variable

byte[] audioBuffer = new byte[1024];
int totalBytesRead = 0;

try (FileOutputStream fos = new FileOutputStream(audioFile)) {
// First write WAV file header (placeholder, fill actual values later)
writeWavHeader(fos, 0, 0);

while (isRecording) {
int read = audioRecord.read(audioBuffer, 0, audioBuffer.length);
if (read > 0) {
// Write audio data to file
fos.write(audioBuffer, 0, read);
totalBytesRead += read;
}
}

// After recording is complete, update the actual data size in the WAV file header
updateWavHeader(audioFile, totalBytesRead);

} catch (IOException e) {
Log.e("AudioRecord", "File write failed: " + e.getMessage());
}
}

// Write WAV file header (initial placeholder version)
private void writeWavHeader(FileOutputStream out, long totalAudioLen, long totalDataLen) throws IOException {
long sampleRate = SAMPLE_RATE_IN_HZ;
int channels = 1; // Mono
int bitsPerSample = 16; // 16-bit

byte[] header = new byte[44];

// RIFF/WAVE header
header[0] = 'R'; header[1] = 'I'; header[2] = 'F'; header[3] = 'F';
header[4] = (byte) (totalDataLen & 0xff);
header[5] = (byte) ((totalDataLen >> 8) & 0xff);
header[6] = (byte) ((totalDataLen >> 16) & 0xff);
header[7] = (byte) ((totalDataLen >> 24) & 0xff);

// WAVE
header[8] = 'W'; header[9] = 'A'; header[10] = 'V'; header[11] = 'E';

// 'fmt ' chunk
header[12] = 'f'; header[13] = 'm'; header[14] = 't'; header[15] = ' ';

// 4 bytes: size of 'fmt ' chunk
header[16] = 16; header[17] = 0; header[18] = 0; header[19] = 0;

// format = 1 (PCM)
header[20] = 1; header[21] = 0;

// number of channels
header[22] = (byte) channels; header[23] = 0;

// sample rate
header[24] = (byte) (sampleRate & 0xff);
header[25] = (byte) ((sampleRate >> 8) & 0xff);
header[26] = (byte) ((sampleRate >> 16) & 0xff);
header[27] = (byte) ((sampleRate >> 24) & 0xff);

// byte rate
long byteRate = sampleRate * channels * bitsPerSample / 8;
header[28] = (byte) (byteRate & 0xff);
header[29] = (byte) ((byteRate >> 8) & 0xff);
header[30] = (byte) ((byteRate >> 16) & 0xff);
header[31] = (byte) ((byteRate >> 24) & 0xff);

// block align
header[32] = (byte) (channels * bitsPerSample / 8);
header[33] = 0;

// bits per sample
header[34] = (byte) bitsPerSample;
header[35] = 0;

// data chunk
header[36] = 'd'; header[37] = 'a'; header[38] = 't'; header[39] = 'a';
header[40] = (byte) (totalAudioLen & 0xff);
header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
header[43] = (byte) ((totalAudioLen >> 24) & 0xff);

out.write(header, 0, 44);
}

// Update actual data size in WAV file header
private void updateWavHeader(File file, int totalAudioLen) {
try (RandomAccessFile raf = new RandomAccessFile(file, "rw")) {
// Update total file size (file size - 8)
long totalDataLen = totalAudioLen + 36; // 36 = 44 - 8
raf.seek(4);
raf.write((int) (totalDataLen & 0xff));
raf.write((int) ((totalDataLen >> 8) & 0xff));
raf.write((int) ((totalDataLen >> 16) & 0xff));
raf.write((int) ((totalDataLen >> 24) & 0xff));

// Update audio data size
raf.seek(40);
raf.write((int) (totalAudioLen & 0xff));
raf.write((int) ((totalAudioLen >> 8) & 0xff));
raf.write((int) ((totalAudioLen >> 16) & 0xff));
raf.write((int) ((totalAudioLen >> 24) & 0xff));
} catch (IOException e) {
Log.e("AudioRecord", "Error updating WAV header: " + e.getMessage());
}
}

@Override
protected void onDestroy() {
super.onDestroy();
if (audioRecord != null) {
audioRecord.release(); // Ensure resource release
}
}
}

Step 3: Start and Stop Recording

Similarly, use buttons or other controls to control the start and stop of recording:

Button startButton = findViewById(R.id.startButton);
Button stopButton = findViewById(R.id.stopButton);

startButton.setOnClickListener(v -> startRecording());
stopButton.setOnClickListener(v -> stopRecording());

Method 3: Save Recording Data to File​

If you wish to save the audio data to a file, you can use the write method of AudioRecord to save the audio stream to a file, or directly use MediaRecorder to save it as a .3gp format file.


Other Considerations​

  1. Permission Issues: Consistent with the camera, it is recommended to enable microphone permission by default through system settings to avoid dynamic permission requests.
  2. Device Compatibility: Ensure the device supports microphone functionality, check the features of AudioManager and MediaRecorder.
  3. Thread Management: If using AudioRecord, audio recording needs to be done in a background thread, otherwise it may cause ANR (Application Not Responding).
  4. If you need simple recording functionality, you can use MediaRecorder.
  5. If you need finer control (e.g., real-time audio processing), you can use AudioRecord.

🖥️ Screen Display Usage Method​

  • General Layout Display: Use standard Android layouts to display relevant content on the screen.
  • Layout Implementation Method: Use basic Android layout methods or custom UI to achieve display content that meets resolution requirements.
  • Circular Screen Adaptation:
    • System resolution is 500×500
    • The actual effective display area is a circular area with a radius of 250 pixels
    • Pay special attention to the boundary adaptation of the circular area during layout.