Loading packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java +59 −63 Original line number Diff line number Diff line Loading @@ -27,32 +27,29 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.drawable.Icon; import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; import android.media.MediaRecorder; import android.media.ThumbnailUtils; import android.media.projection.MediaProjection; import android.media.projection.MediaProjectionManager; import android.net.Uri; import android.os.Environment; import android.os.IBinder; import android.provider.MediaStore; import android.provider.Settings; import android.util.DisplayMetrics; import android.util.Log; import android.util.Size; import android.view.Surface; import android.widget.Toast; import androidx.core.content.FileProvider; import com.android.systemui.R; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.text.SimpleDateFormat; import java.util.Date; Loading @@ -79,12 +76,10 @@ public class RecordingService extends Service { private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE"; private static final int TOTAL_NUM_TRACKS = 1; private static final String RECORD_DIR = "Captures"; // TODO: use a translatable string private static final int VIDEO_BIT_RATE = 6000000; private static final int VIDEO_FRAME_RATE = 30; private static final int AUDIO_BIT_RATE = 16; private static final int AUDIO_SAMPLE_RATE = 44100; private static final String FILE_PROVIDER = "com.android.systemui.fileprovider"; private MediaProjectionManager mMediaProjectionManager; private MediaProjection mMediaProjection; Loading Loading @@ -120,11 +115,11 @@ public class RecordingService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "RecordingService is starting"); if (intent == null) { return Service.START_NOT_STICKY; } String action = intent.getAction(); Log.d(TAG, "onStartCommand " + action); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); Loading Loading @@ -160,41 +155,7 @@ public class RecordingService extends Service { case ACTION_STOP: stopRecording(); String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'") .format(new Date()); ContentValues values = new ContentValues(); values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName); values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4"); values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis()); values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis()); ContentResolver resolver = getContentResolver(); Uri collectionUri = MediaStore.Video.Media.getContentUri( MediaStore.VOLUME_EXTERNAL_PRIMARY); Uri itemUri = resolver.insert(collectionUri, values); File recordDir = new File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), RECORD_DIR); recordDir.mkdirs(); Path path = new File(recordDir, fileName).toPath(); try { // Move file out of temp directory Files.move(mTempFile.toPath(), path); // Add to the mediastore OutputStream os = resolver.openOutputStream(itemUri, "w"); Files.copy(path, os); os.close(); Notification notification = createSaveNotification(itemUri, path); notificationManager.notify(NOTIFICATION_ID, notification); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG) .show(); } saveRecording(notificationManager); break; case ACTION_PAUSE: Loading @@ -208,8 +169,7 @@ public class RecordingService extends Service { break; case ACTION_SHARE: File shareFile = new File(intent.getStringExtra(EXTRA_PATH)); Uri shareUri = FileProvider.getUriForFile(this, FILE_PROVIDER, shareFile); Uri shareUri = Uri.parse(intent.getStringExtra(EXTRA_PATH)); Intent shareIntent = new Intent(Intent.ACTION_SEND) .setType("video/mp4") Loading @@ -229,8 +189,10 @@ public class RecordingService extends Service { // Close quick shade sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); File file = new File(intent.getStringExtra(EXTRA_PATH)); if (file.delete()) { ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse(intent.getStringExtra(EXTRA_PATH)); resolver.delete(uri, null, null); Toast.makeText( this, R.string.screenrecord_delete_description, Loading @@ -238,11 +200,7 @@ public class RecordingService extends Service { // Remove notification notificationManager.cancel(NOTIFICATION_ID); } else { Log.e(TAG, "Error deleting screen recording!"); Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG) .show(); } Log.d(TAG, "Deleted recording " + uri); break; } return Service.START_STICKY; Loading Loading @@ -313,6 +271,7 @@ public class RecordingService extends Service { mMediaRecorder.start(); } catch (IOException e) { Log.e(TAG, "Error starting screen recording: " + e.getMessage()); e.printStackTrace(); throw new RuntimeException(e); } Loading Loading @@ -370,9 +329,7 @@ public class RecordingService extends Service { notificationManager.notify(NOTIFICATION_ID, mRecordingNotificationBuilder.build()); } private Notification createSaveNotification(Uri uri, Path path) { Log.d(TAG, "Screen recording saved to " + uri.toString() + ", " + path.toString()); private Notification createSaveNotification(Uri uri) { Intent viewIntent = new Intent(Intent.ACTION_VIEW) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION) .setDataAndType(uri, "video/mp4"); Loading Loading @@ -411,8 +368,15 @@ public class RecordingService extends Service { .setAutoCancel(true); // Add thumbnail if available Bitmap thumbnailBitmap = ThumbnailUtils.createVideoThumbnail(path.toString(), MediaStore.Video.Thumbnails.MINI_KIND); Bitmap thumbnailBitmap = null; try { ContentResolver resolver = getContentResolver(); Size size = Point.convert(MediaStore.ThumbnailConstants.MINI_SIZE); thumbnailBitmap = resolver.loadThumbnail(uri, size, null); } catch (IOException e) { Log.e(TAG, "Error creating thumbnail: " + e.getMessage()); e.printStackTrace(); } if (thumbnailBitmap != null) { Notification.BigPictureStyle pictureStyle = new Notification.BigPictureStyle() .bigPicture(thumbnailBitmap) Loading @@ -434,6 +398,38 @@ public class RecordingService extends Service { stopSelf(); } private void saveRecording(NotificationManager notificationManager) { String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'") .format(new Date()); ContentValues values = new ContentValues(); values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName); values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4"); values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis()); values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis()); ContentResolver resolver = getContentResolver(); Uri collectionUri = MediaStore.Video.Media.getContentUri( MediaStore.VOLUME_EXTERNAL_PRIMARY); Uri itemUri = resolver.insert(collectionUri, values); try { // Add to the mediastore OutputStream os = resolver.openOutputStream(itemUri, "w"); Files.copy(mTempFile.toPath(), os); os.close(); Notification notification = createSaveNotification(itemUri); notificationManager.notify(NOTIFICATION_ID, notification); mTempFile.delete(); } catch (IOException e) { Log.e(TAG, "Error saving screen recording: " + e.getMessage()); Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG) .show(); } } private void setTapsVisible(boolean turnOn) { int value = turnOn ? 1 : 0; Settings.System.putInt(getApplicationContext().getContentResolver(), Loading Loading
packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java +59 −63 Original line number Diff line number Diff line Loading @@ -27,32 +27,29 @@ import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Point; import android.graphics.drawable.Icon; import android.hardware.display.DisplayManager; import android.hardware.display.VirtualDisplay; import android.media.MediaRecorder; import android.media.ThumbnailUtils; import android.media.projection.MediaProjection; import android.media.projection.MediaProjectionManager; import android.net.Uri; import android.os.Environment; import android.os.IBinder; import android.provider.MediaStore; import android.provider.Settings; import android.util.DisplayMetrics; import android.util.Log; import android.util.Size; import android.view.Surface; import android.widget.Toast; import androidx.core.content.FileProvider; import com.android.systemui.R; import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.text.SimpleDateFormat; import java.util.Date; Loading @@ -79,12 +76,10 @@ public class RecordingService extends Service { private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE"; private static final int TOTAL_NUM_TRACKS = 1; private static final String RECORD_DIR = "Captures"; // TODO: use a translatable string private static final int VIDEO_BIT_RATE = 6000000; private static final int VIDEO_FRAME_RATE = 30; private static final int AUDIO_BIT_RATE = 16; private static final int AUDIO_SAMPLE_RATE = 44100; private static final String FILE_PROVIDER = "com.android.systemui.fileprovider"; private MediaProjectionManager mMediaProjectionManager; private MediaProjection mMediaProjection; Loading Loading @@ -120,11 +115,11 @@ public class RecordingService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d(TAG, "RecordingService is starting"); if (intent == null) { return Service.START_NOT_STICKY; } String action = intent.getAction(); Log.d(TAG, "onStartCommand " + action); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); Loading Loading @@ -160,41 +155,7 @@ public class RecordingService extends Service { case ACTION_STOP: stopRecording(); String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'") .format(new Date()); ContentValues values = new ContentValues(); values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName); values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4"); values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis()); values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis()); ContentResolver resolver = getContentResolver(); Uri collectionUri = MediaStore.Video.Media.getContentUri( MediaStore.VOLUME_EXTERNAL_PRIMARY); Uri itemUri = resolver.insert(collectionUri, values); File recordDir = new File(getExternalFilesDir(Environment.DIRECTORY_MOVIES), RECORD_DIR); recordDir.mkdirs(); Path path = new File(recordDir, fileName).toPath(); try { // Move file out of temp directory Files.move(mTempFile.toPath(), path); // Add to the mediastore OutputStream os = resolver.openOutputStream(itemUri, "w"); Files.copy(path, os); os.close(); Notification notification = createSaveNotification(itemUri, path); notificationManager.notify(NOTIFICATION_ID, notification); } catch (IOException e) { e.printStackTrace(); Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG) .show(); } saveRecording(notificationManager); break; case ACTION_PAUSE: Loading @@ -208,8 +169,7 @@ public class RecordingService extends Service { break; case ACTION_SHARE: File shareFile = new File(intent.getStringExtra(EXTRA_PATH)); Uri shareUri = FileProvider.getUriForFile(this, FILE_PROVIDER, shareFile); Uri shareUri = Uri.parse(intent.getStringExtra(EXTRA_PATH)); Intent shareIntent = new Intent(Intent.ACTION_SEND) .setType("video/mp4") Loading @@ -229,8 +189,10 @@ public class RecordingService extends Service { // Close quick shade sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); File file = new File(intent.getStringExtra(EXTRA_PATH)); if (file.delete()) { ContentResolver resolver = getContentResolver(); Uri uri = Uri.parse(intent.getStringExtra(EXTRA_PATH)); resolver.delete(uri, null, null); Toast.makeText( this, R.string.screenrecord_delete_description, Loading @@ -238,11 +200,7 @@ public class RecordingService extends Service { // Remove notification notificationManager.cancel(NOTIFICATION_ID); } else { Log.e(TAG, "Error deleting screen recording!"); Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG) .show(); } Log.d(TAG, "Deleted recording " + uri); break; } return Service.START_STICKY; Loading Loading @@ -313,6 +271,7 @@ public class RecordingService extends Service { mMediaRecorder.start(); } catch (IOException e) { Log.e(TAG, "Error starting screen recording: " + e.getMessage()); e.printStackTrace(); throw new RuntimeException(e); } Loading Loading @@ -370,9 +329,7 @@ public class RecordingService extends Service { notificationManager.notify(NOTIFICATION_ID, mRecordingNotificationBuilder.build()); } private Notification createSaveNotification(Uri uri, Path path) { Log.d(TAG, "Screen recording saved to " + uri.toString() + ", " + path.toString()); private Notification createSaveNotification(Uri uri) { Intent viewIntent = new Intent(Intent.ACTION_VIEW) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION) .setDataAndType(uri, "video/mp4"); Loading Loading @@ -411,8 +368,15 @@ public class RecordingService extends Service { .setAutoCancel(true); // Add thumbnail if available Bitmap thumbnailBitmap = ThumbnailUtils.createVideoThumbnail(path.toString(), MediaStore.Video.Thumbnails.MINI_KIND); Bitmap thumbnailBitmap = null; try { ContentResolver resolver = getContentResolver(); Size size = Point.convert(MediaStore.ThumbnailConstants.MINI_SIZE); thumbnailBitmap = resolver.loadThumbnail(uri, size, null); } catch (IOException e) { Log.e(TAG, "Error creating thumbnail: " + e.getMessage()); e.printStackTrace(); } if (thumbnailBitmap != null) { Notification.BigPictureStyle pictureStyle = new Notification.BigPictureStyle() .bigPicture(thumbnailBitmap) Loading @@ -434,6 +398,38 @@ public class RecordingService extends Service { stopSelf(); } private void saveRecording(NotificationManager notificationManager) { String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'") .format(new Date()); ContentValues values = new ContentValues(); values.put(MediaStore.Video.Media.DISPLAY_NAME, fileName); values.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4"); values.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis()); values.put(MediaStore.Video.Media.DATE_TAKEN, System.currentTimeMillis()); ContentResolver resolver = getContentResolver(); Uri collectionUri = MediaStore.Video.Media.getContentUri( MediaStore.VOLUME_EXTERNAL_PRIMARY); Uri itemUri = resolver.insert(collectionUri, values); try { // Add to the mediastore OutputStream os = resolver.openOutputStream(itemUri, "w"); Files.copy(mTempFile.toPath(), os); os.close(); Notification notification = createSaveNotification(itemUri); notificationManager.notify(NOTIFICATION_ID, notification); mTempFile.delete(); } catch (IOException e) { Log.e(TAG, "Error saving screen recording: " + e.getMessage()); Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG) .show(); } } private void setTapsVisible(boolean turnOn) { int value = turnOn ? 1 : 0; Settings.System.putInt(getApplicationContext().getContentResolver(), Loading