Как записать экран в Android более 3 минут программно?

Я пытаюсь работать с записью экрана на Android 4.4. Я нашел пример кода, но там не могу написать более 3 минут видео. Как я могу обойти это ограничение Android? В некоторых приложениях, таких как Rec. это ограничение было снято.

Это пример, который я использую.

public class MainActivity extends Activity {
private static final int RUNNING_NOTIFICATION_ID = 73;
private static final int FINISHED_NOTIFICATION_ID = 1337;

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

    if (savedInstanceState == null) {
        getFragmentManager().beginTransaction()
                .add(R.id.container, new MainFragment())
                .commit();
    }
}

public static class MainFragment extends Fragment {
    private Context mContext;

    private EditText mWidthEditText;
    private EditText mHeightEditText;
    private EditText mBitrateEditText;
    private EditText mTimeEditText;
    private Button mRecordButton;

    public MainFragment() {
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_main, container, false);

        mContext = getActivity();

        mRecordButton = (Button) rootView.findViewById(R.id.btn_record);
        mRecordButton.setOnClickListener(RecordOnClickListener);

        mWidthEditText = (EditText) rootView.findViewById(R.id.et_width);
        mHeightEditText = (EditText) rootView.findViewById(R.id.et_height);
        mBitrateEditText = (EditText) rootView.findViewById(R.id.et_bitrate);
        mBitrateEditText.addTextChangedListener(BitrateTextWatcher);
        mTimeEditText = (EditText) rootView.findViewById(R.id.et_time);
        mTimeEditText.addTextChangedListener(TimeTextWatcher);

        return rootView;
    }

    private TextWatcher BitrateTextWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
            // Not used.
        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
            if (TextUtils.isEmpty(charSequence)) {
                return;
            }

            int value = Integer.valueOf(charSequence.toString());
            if (value > 50 || value == 0) {
                mBitrateEditText.setError(mContext.getString(R.string.error_bitrate_edittext));
                return;
            }

            mTimeEditText.setError(null);
        }

        @Override
        public void afterTextChanged(Editable editable) {
            // Not used.
        }
    };

    private TextWatcher TimeTextWatcher = new TextWatcher() {
        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
            // Not used.
        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
            if (TextUtils.isEmpty(charSequence)) {
                return;
            }

            int value = Integer.valueOf(charSequence.toString());
            if (value > 180 || value == 0) {
                mTimeEditText.setError(mContext.getString(R.string.error_time_editext));
                return;
            }

            mTimeEditText.setError(null);
        }

        @Override
        public void afterTextChanged(Editable editable) {
            // Not used.
        }
    };

    private View.OnClickListener RecordOnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (!TextUtils.isEmpty(mTimeEditText.getError()) || !TextUtils.isEmpty(mBitrateEditText.getError())) {
                Toast.makeText(mContext, mContext.getString(R.string.toast_invalid_values), Toast.LENGTH_LONG).show();
                return;
            }

            boolean widthSet = !TextUtils.isEmpty(mWidthEditText.getText());
            boolean heightSet = !TextUtils.isEmpty(mHeightEditText.getText());
            if ((!widthSet && heightSet) || (widthSet && !heightSet)) {
                Toast.makeText(mContext, mContext.getString(R.string.error_invalid_wxh), Toast.LENGTH_LONG).show();
                return;
            }

            boolean bitrateSet = !TextUtils.isEmpty(mBitrateEditText.getText());
            boolean timeSet = !TextUtils.isEmpty(mTimeEditText.getText());

            StringBuilder stringBuilder = new StringBuilder("/system/bin/screenrecord");
            if (widthSet) {
                stringBuilder.append(" --size ").append(mWidthEditText.getText()).append("x").append(mHeightEditText.getText());
            }
            if (bitrateSet) {
                stringBuilder.append(" --bit-rate ").append(mBitrateEditText.getText());
            }
            if (timeSet) {
                stringBuilder.append(" --time-limit ").append(mTimeEditText.getText());
            }

            // TODO User definable location.
            stringBuilder.append(" ").append(Environment.getExternalStorageDirectory().toString()).append("/recording.mp4");
            Log.d("TAG", "comamnd: " + stringBuilder.toString());

            try {
                new SuTask(stringBuilder.toString().getBytes("ASCII")).execute();

            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
    };

    private class SuTask extends AsyncTask<Boolean, Void, Boolean> {
        private final byte[] mCommand;

        public SuTask(byte[] command) {
            super();
            this.mCommand = command;
        }

        @Override
        protected Boolean doInBackground(Boolean... booleans) {
            try {
                Process sh = Runtime.getRuntime().exec("su", null, null);
                OutputStream outputStream = sh.getOutputStream();
                outputStream.write(mCommand);
                outputStream.flush();
                outputStream.close();

                final NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE);
                notificationManager.notify(RUNNING_NOTIFICATION_ID, createRunningNotification(mContext));

                sh.waitFor();
                return true;

            } catch (InterruptedException e) {
                e.printStackTrace();
                Toast.makeText(mContext, mContext.getString(R.string.error_start_recording), Toast.LENGTH_LONG).show();

            } catch (IOException e) {
                e.printStackTrace();
                Toast.makeText(mContext, mContext.getString(R.string.error_start_recording), Toast.LENGTH_LONG).show();
            }

            return false;
        }

        @Override
        protected void onPostExecute(Boolean bool) {
            super.onPostExecute(bool);
            if (bool) {
                final NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(NOTIFICATION_SERVICE);
                notificationManager.cancel(RUNNING_NOTIFICATION_ID);

                File file = new File(Environment.getExternalStorageDirectory().toString() + "/recording.mp4");
                notificationManager.notify(FINISHED_NOTIFICATION_ID, createFinishedNotification(mContext, file));
            }
        }

        private Notification createRunningNotification(Context context) {
            Notification.Builder mBuilder = new Notification.Builder(context)
                    .setSmallIcon(android.R.drawable.stat_notify_sdcard)
                    .setContentTitle(context.getResources().getString(R.string.app_name))
                    .setContentText("Recording Running")
                    .setTicker("Recording Running")
                    .setPriority(Integer.MAX_VALUE)
                    .setOngoing(true);

            return mBuilder.build();
        }

        private Notification createFinishedNotification(Context context, File file) {
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.fromFile(file), "video/mp4");

            PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent,
                    PendingIntent.FLAG_UPDATE_CURRENT);

            Notification.Builder mBuilder = new Notification.Builder(context)
                    .setSmallIcon(android.R.drawable.stat_notify_sdcard)
                    .setContentTitle(context.getResources().getString(R.string.app_name))
                    .setContentText("Recording Finished")
                    .setTicker("Recording Finished")
                    .setContentIntent(pendingIntent)
                    .setOngoing(false)
                    .setAutoCancel(true);

            return mBuilder.build();
        }
    }
}

}

1 ответ

Вы не можете обойти 3-минутный лимит. Вы можете объединить несколько 3-минутных видео для создания более длинных видео.

Если вы хотите написать свои собственные возможности записи экрана, вам нужно будет постоянно делать скриншоты в потоке и конвертировать все эти изображения в видео. Надеюсь, есть некоторые библиотеки, которые вы можете использовать.

Другой альтернативой является запуск приложения записи экрана из вашего приложения, но для этого потребуется, чтобы на устройстве также было установлено приложение записи экрана.

Вы можете создать скрипт для этого. Согласно документации ADB, способ записи из командной строки - это вызов adb shell screenrecord [options] filename, Добавьте это в сценарий со счетчиком циклов для имени, и вы можете получить хороший список видео. Вытащите их из SDCard с adb pull /sdcard/*,

Пример скрипта, взятого xda-developers for Windows:

CALL :Record
SET /a var1=0
:record
SET /a var1+=1
SET /a name=%var1%
adb shell screenrecord /sdcard/recording%name%.mp4 --bit-rate 3145728
GOTO :record

Сохраните это как "record.bat", и вы готовы идти:)

Другие вопросы по тегам