package com.cooleshow.musicmerge.ui; import android.animation.ObjectAnimator; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.ActivityInfo; import android.graphics.Color; import android.graphics.Rect; import android.graphics.SurfaceTexture; import android.graphics.drawable.Drawable; import android.media.MediaPlayer; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; import android.view.Surface; import android.view.TextureView; import android.view.View; import android.view.animation.LinearInterpolator; import android.widget.FrameLayout; import android.widget.SeekBar; import com.alibaba.android.arouter.facade.annotation.Route; import com.alibaba.android.arouter.launcher.ARouter; import com.cooleshow.base.bean.ShareIntentBean; import com.cooleshow.base.common.WebConstants; import com.cooleshow.base.constanst.Constants; import com.cooleshow.base.constanst.ShareType; import com.cooleshow.base.constanst.UploadConstants; import com.cooleshow.base.router.RouterPath; import com.cooleshow.base.ui.activity.BaseMVPActivity; import com.cooleshow.base.utils.ClipboardUtils; import com.cooleshow.base.utils.FileUtils; import com.cooleshow.base.utils.GlideUtils; import com.cooleshow.base.utils.GsonUtils; import com.cooleshow.base.utils.JumpUtils; import com.cooleshow.base.utils.LOG; import com.cooleshow.base.utils.MyFileUtils; import com.cooleshow.base.utils.NumberUtils; import com.cooleshow.base.utils.SizeUtils; import com.cooleshow.base.utils.TimeUtils; import com.cooleshow.base.utils.ToastUtil; import com.cooleshow.base.utils.UrlUtils; import com.cooleshow.base.utils.helper.CommonShareHelper; import com.cooleshow.base.utils.helper.QMUIStatusBarHelper; import com.cooleshow.base.utils.helper.upload.UploadHelper; import com.cooleshow.base.widgets.dialog.CommonConfirmDialog; import com.cooleshow.base.widgets.dialog.CommonConfirmDialog2; import com.cooleshow.base.widgets.dialog.ShareDialog; import com.cooleshow.musicmerge.R; import com.cooleshow.musicmerge.bean.MusicDataBean; import com.cooleshow.musicmerge.bean.MusicInfoBean; import com.cooleshow.musicmerge.bean.MusicMergeConfigBean; import com.cooleshow.musicmerge.callback.ResultCallback; import com.cooleshow.musicmerge.contract.MusicFileHandleContract; import com.cooleshow.musicmerge.databinding.AcMusicHandleLayoutBinding; import com.cooleshow.musicmerge.helper.MixHelper; import com.cooleshow.musicmerge.player.CustomPlayer; import com.cooleshow.musicmerge.presenter.MusicFileHandlePresenter; import com.cooleshow.musicmerge.viewmodel.MusicMergeViewModel; import com.cooleshow.musicmerge.widget.MergeLoadingTipDialog; import com.luck.picture.lib.PictureSelector; import com.luck.picture.lib.entity.LocalMedia; import com.umeng.socialize.UMShareAPI; import com.umeng.socialize.UMShareListener; import com.umeng.socialize.bean.SHARE_MEDIA; import java.io.File; import java.util.List; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.lifecycle.ViewModelProvider; /** * Author by pq, Date on 2023/8/28. */ @Route(path = RouterPath.MusicTuner.MUSIC_MERGE_PAGE) public class MusicHandleActivity extends BaseMVPActivity implements View.OnClickListener, MusicFileHandleContract, TextureView.SurfaceTextureListener, UMShareListener { public static final int REQUEST_CODE_LOCAL = 0x19; public static final int REQUEST_CODE_LOCAL_VIDEO_COVER = 0x20; public static final int REQUEST_CODE_VIDEO_COVER = 0x29; public static final int MAX_ADJUSTMENT = 10; private CustomPlayer player1; private CustomPlayer player2; private String accompanyUrl; private String recordFilePath; private MusicHandleSettingFragment mSettingFragment; private boolean isVideo; private TextureView mSurfaceView; private SurfaceTexture mSurfaceTexture; private int videoWidth; private int videoHeight; private Handler mHandler = new Handler(Looper.getMainLooper()); private String mRecordId; private String worksId; private String imgCover; private String des; private ObjectAnimator mRotateAnimation; private ObjectAnimator mAlbumRotationAnimator; private String originalFileUrl = ""; private String mTitle; private MusicMergeViewModel mViewModel; private boolean isNeedFinishPage = false; private boolean isNeedResetScreenOrientation = true; private MergeLoadingTipDialog mLoadingTipDialog; private static int MAX_STEP = 3; private static final int MAX_PROGRESS = 100; private int currentStep = 0; private int firstPlayDuration = 0; private int secondPlayDuration = 0; private int defaultDelay = 0;//此字段用于录音文件前面缓冲以及设备延迟造成的空白延迟字段 private int evaluateDelay = 0;//此字段记录给IOS使用 @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); QMUIStatusBarHelper.hideStatusBar(this); } @Override protected void initView() { mTitle = getIntent().getStringExtra("title"); viewBinding.tvTitle.setText(mTitle); int c_orientation = getIntent().getIntExtra("c_orientation", ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); isNeedResetScreenOrientation = c_orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; } private void initFragment() { mSettingFragment = new MusicHandleSettingFragment(); Bundle bundle = new Bundle(); bundle.putString("accompanyUrl", accompanyUrl); bundle.putInt("defaultDelay", defaultDelay); mSettingFragment.setArguments(bundle); getSupportFragmentManager().beginTransaction().replace(R.id.fl_setting, mSettingFragment).commitAllowingStateLoss(); } private void initSurfaceView() { initVideoUIStyle(); mViewModel.getVideoFilePath().setValue(recordFilePath); viewBinding.groupAudioView.setVisibility(View.GONE); viewBinding.flSurface.setVisibility(View.VISIBLE); viewBinding.viewVideoTopBg.setVisibility(View.VISIBLE); viewBinding.viewVideoBottomBg.setVisibility(View.VISIBLE); viewBinding.viewVideoBg.setVisibility(View.VISIBLE); mSurfaceView = new TextureView(MusicHandleActivity.this); mSurfaceView.setSurfaceTextureListener(this); FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT); layoutParams.gravity = Gravity.CENTER; viewBinding.flSurface.addView(mSurfaceView, layoutParams); } private void initVideoUIStyle() { viewBinding.tvTitle.setTextColor(Color.WHITE); viewBinding.ivBack.setImageResource(com.cooleshow.base.R.drawable.ic_back_white); viewBinding.ivPlay.setImageResource(R.drawable.icon_music_merge_play_white); viewBinding.tvCurrentProgress.setTextColor(Color.WHITE); viewBinding.tvTotalProgress.setTextColor(Color.WHITE); viewBinding.seekPlay.setThumb(getResources().getDrawable(R.drawable.shape_volume_progreesbar_thumb2)); setSeekBarProgressDrawable(viewBinding.seekPlay, getResources().getDrawable(R.drawable.shape_play_progress_seekbar_bg2)); viewBinding.tvTotalProgress2.setTextColor(Color.WHITE); viewBinding.seekPlay2.setThumb(getResources().getDrawable(R.drawable.shape_volume_progreesbar_thumb2)); viewBinding.tvCurrentProgress2.setTextColor(Color.WHITE); setSeekBarProgressDrawable(viewBinding.seekPlay2, getResources().getDrawable(R.drawable.shape_play_progress_seekbar_bg2)); } private void setSeekBarProgressDrawable(SeekBar seekBarProgress, Drawable drawable) { Rect bounds = seekBarProgress.getProgressDrawable().getBounds(); seekBarProgress.setProgressDrawable(drawable); seekBarProgress.getProgressDrawable().setBounds(bounds); } @Override public void initData() { super.initData(); mRecordId = getIntent().getStringExtra("recordId"); worksId = getIntent().getStringExtra("worksId"); imgCover = getIntent().getStringExtra("coverImg"); defaultDelay = getIntent().getIntExtra("defaultDelay", 0); evaluateDelay = getIntent().getIntExtra("evaluateDelay", 0); loadCover(); if (TextUtils.isEmpty(mRecordId)) { ToastUtil.getInstance().showShort("作品生成失败"); finish(); return; } accompanyUrl = getIntent().getStringExtra("accompanyUrl"); recordFilePath = getIntent().getStringExtra("recordFilePath"); initLoadingDialog(); initViewModel(); initFragment(); initListener(); initPlayer(); LOG.i("recordFilePath:" + recordFilePath); LOG.i("accompanyUrl:" + accompanyUrl); if (!checkRecordFile()) { if (!TextUtils.isEmpty(worksId)) { presenter.getDetail(worksId); } else { ToastUtil.getInstance().showShort("作品生成失败"); finish(); } } else { preLoad(); } } private void initViewModel() { ViewModelProvider.AndroidViewModelFactory instance = ViewModelProvider.AndroidViewModelFactory .getInstance(getApplication()); mViewModel = new ViewModelProvider(this, instance) .get(MusicMergeViewModel.class); mViewModel.getWorksId().setValue(worksId); refreshMusicInfo(imgCover); } private void preLoad() { isVideo = MyFileUtils.isVideo(recordFilePath); LOG.i("isVideo:" + isVideo); mViewModel.getIsVideoFile().setValue(isVideo); boolean b = checkAccompanimentMp3File(); if (b) { preparePlay(); } } private void preparePlay() { if (isVideo) { initSurfaceView(); } else { toPlay(getAccompanyPath()); } } private void loadCover() { GlideUtils.INSTANCE.loadImage(this, imgCover, viewBinding.ivCover, R.drawable.icon_default_music_song_cover); } @Override protected MusicFileHandlePresenter createPresenter() { return new MusicFileHandlePresenter(); } private void initListener() { viewBinding.ivBack.setOnClickListener(this); viewBinding.ivPlay.setOnClickListener(this); viewBinding.ivUnfoldSentting.setOnClickListener(this); mSettingFragment.setEventListener(new MusicHandleSettingFragment.OnEventListener() { @Override public void onVolumeChange(int type, float value) { if (type == MusicHandleSettingFragment.RECORD_TYPE) { player1.setVolume(value); } else { player2.setVolume(value); } } @Override public void onOffsetValueChange(int value) { aligningAccompany(value); } @Override public void toMix(int offsetValue, float volume1, float volume2, boolean isNeedNotify) { MAX_STEP = 3; checkCoverToUpload(); if (isVideo) { startMixForMp4(getAccompanyPath(), recordFilePath, offsetValue, volume1, volume2, isNeedNotify); } else { startMix(getAccompanyPath(), recordFilePath, offsetValue, volume1, volume2, isNeedNotify); } } @Override public void hideSetting() { handleSettingVisibility(); } @Override public void saveDraft() { //上传原始视频 以及 相关调节参数 toSaveDraft(); } }); viewBinding.seekPlay.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { if (fromUser) { handleSeekEvent(); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); } private void checkCoverToUpload() { MusicInfoBean value = mViewModel.getMusicInfoLiveData().getValue(); if (value != null) { String preCover = value.getPreCover(); String videoCover = value.getVideoCover(); LOG.i("preCover:" + preCover); LOG.i("videoCover:" + videoCover); if (!TextUtils.isEmpty(preCover)) { presenter.upLoadImage(null, preCover, false); } if (!TextUtils.isEmpty(videoCover)) { presenter.upLoadImage(null, videoCover, true); } } } private void toSaveDraft() { if (!TextUtils.isEmpty(recordFilePath)) { if (!TextUtils.isEmpty(originalFileUrl)) { MAX_STEP = 1; toShowLoading(0, getString(R.string.save_draft_tip)); toNotifyDraft(originalFileUrl); } else { MAX_STEP = 2; uploadDraft(recordFilePath); } } } private void uploadDraft(String filePath) { currentStep = 0; File file = new File(filePath); if (!file.exists()) { return; } toSetLoadingCancelable(false); toShowLoading(getCurrentProgress(0), getString(R.string.updload_draft_tip)); UploadHelper uploadHelper = new UploadHelper(null, UploadConstants.UPLOAD_TYPE_HOMEWORK); uploadHelper.setUpLoadCallBack(new UploadHelper.UpLoadCallBack() { @Override protected void onSuccess(String url) { toUpdateLoadingText(getCurrentProgress(100), getString(R.string.updload_draft_tip)); toNotifyDraft(url); } @Override protected void onFailure() { runOnUiThread(new Runnable() { @Override public void run() { hideLoading(); ToastUtil.getInstance().showShort("草稿上传失败,请重试"); } }); } @Override public void onUploadProgress(double v) { Log.i("pq", "onUploadProgress" + v); // UiUtils.convertDouble(v) toUpdateLoadingText(getCurrentProgress((int) v), getString(R.string.updload_draft_tip)); } }); uploadHelper.setLoadingTip(getString(R.string.updload_draft_tip)); uploadHelper.uploadFile(file); } private void upload(String filePath) { currentStep = 1; File file = new File(filePath); if (!file.exists()) { return; } toUpdateLoadingText(getCurrentProgress(0), getString(R.string.upload_works_tip)); UploadHelper uploadHelper = new UploadHelper(null, UploadConstants.UPLOAD_TYPE_HOMEWORK); uploadHelper.setUpLoadCallBack(new UploadHelper.UpLoadCallBack() { @Override protected void onSuccess(String url) { toUpdateLoadingText(getCurrentProgress(100), getString(R.string.upload_works_tip)); toNotify(url); } @Override protected void onFailure() { runOnUiThread(new Runnable() { @Override public void run() { hideLoading(); ToastUtil.getInstance().showShort("作品上传失败,请重试"); } }); } @Override public void onUploadProgress(double v) { toUpdateLoadingText(getCurrentProgress((int) v), getString(R.string.upload_works_tip)); } }); uploadHelper.setLoadingTip(getString(R.string.upload_works_tip)); uploadHelper.uploadFile(file); } private void toNotify(String url) { String configJson = mSettingFragment.getConfigJson(defaultDelay, evaluateDelay); MusicInfoBean value = mViewModel.getMusicInfoLiveData().getValue(); String videoCover = ""; String cover = imgCover; if (value != null) { des = value.getDes(); String videoCoverResult = value.getVideoCover(); if (UrlUtils.isValidUrl(videoCoverResult)) { videoCover = videoCoverResult; } String cover1 = value.getCover(); if (!TextUtils.isEmpty(cover1)) { cover = cover1; } } presenter.save(mRecordId, url, cover, videoCover, des, configJson); } private void toNotifyDraft(String url) { if (mSettingFragment != null) { String configJson = mSettingFragment.getConfigJson(defaultDelay, evaluateDelay); presenter.saveDraft(mRecordId, url, accompanyUrl, imgCover, configJson); } } public void startMixForMp4(String accompanimentMp3Path, String recordFilePath, int offsetValue, float recordFileVolume, float accompanyFileVolume, boolean isNeedNotify) { currentStep = 0; toSetLoadingCancelable(false); toShowLoading(getCurrentProgress(0), getString(R.string.video_merge_tip)); MixHelper.getInstance().startMixForMp4(accompanimentMp3Path, recordFilePath, offsetValue, recordFileVolume, accompanyFileVolume, new ResultCallback() { @Override public void onSuccess(String s) { if (!checkActivityExist()) { return; } runOnUiThread(new Runnable() { @Override public void run() { toUpdateLoadingText(getCurrentProgress(100), getString(R.string.video_merge_tip)); if (!TextUtils.isEmpty(s)) { if (isNeedNotify) { upload(s); } else { FileUtils.notifySystemToScan(s); ToastUtil.getInstance().showShort("保存成功"); } } else { hideLoading(); ToastUtil.getInstance().showShort("mix onFail"); } } }); } @Override public void onProgress(int progressPercent) { if (!checkActivityExist()) { return; } runOnUiThread(new Runnable() { @Override public void run() { if (currentStep == 0) {//这个进度有延迟,可能不准确,如果到了下一个步骤了就不再触发更新 LOG.i("progressPercent:" + progressPercent); toUpdateLoadingText(getCurrentProgress(progressPercent), getString(R.string.video_merge_tip)); } } }); } @Override public void onFail(int errorCode, String errorStr) { if (!checkActivityExist()) { return; } runOnUiThread(new Runnable() { @Override public void run() { hideLoading(); ToastUtil.getInstance().showShort("mix onFail:" + errorCode + "--reason:" + errorStr); } }); } }); } private void startMix(String accompanimentMp3Path, String recordFilePath, int offsetValue, float recordFileVolume, float accompanyFileVolume, boolean isNeedNotify) { currentStep = 0; toSetLoadingCancelable(false); toShowLoading(getCurrentProgress(0), getString(R.string.audio_merge_tip)); MixHelper.getInstance().startMix(accompanimentMp3Path, recordFilePath, offsetValue, recordFileVolume, accompanyFileVolume, new ResultCallback() { @Override public void onSuccess(String s) { if (!checkActivityExist()) { return; } runOnUiThread(new Runnable() { @Override public void run() { toUpdateLoadingText(getCurrentProgress(100), getString(R.string.audio_merge_tip)); if (!TextUtils.isEmpty(s)) { if (isNeedNotify) { upload(s); } else { FileUtils.notifySystemToScan(s); ToastUtil.getInstance().showShort("保存成功"); } } else { hideLoading(); ToastUtil.getInstance().showShort("mix onFail"); } } }); } @Override public void onProgress(int progressPercent) { if (!checkActivityExist()) { return; } runOnUiThread(new Runnable() { @Override public void run() { if (currentStep == 0) {//这个进度有延迟,可能不准确,如果到了下一个步骤了就不再触发更新 LOG.i("progressPercent:" + progressPercent); toUpdateLoadingText(getCurrentProgress(progressPercent), getString(R.string.audio_merge_tip)); } } }); } @Override public void onFail(int errorCode, String errorStr) { if (!checkActivityExist()) { return; } runOnUiThread(new Runnable() { @Override public void run() { hideLoading(); ToastUtil.getInstance().showShort("mix onFail:" + errorCode + "--reason:" + errorStr); } }); } }); } private void aligningAccompany(int value) { int cu = player1.getCu(); LOG.i("pq", "cu:" + cu); LOG.i("pq", "currentOffsetValue:" + value); int seekResult2 = countAccompanyPosition(cu); LOG.i("pq", "seekResult2:" + seekResult2); player2.seekTo(seekResult2); } private void handleSeekEvent() { int progress = viewBinding.seekPlay.getProgress(); float percent = progress * 1.0f / viewBinding.seekPlay.getMax(); int seekResult = (int) (player1.getTotal() * percent); LOG.i("pq", "seekResult:" + seekResult); int seekResult2 = countAccompanyPosition(seekResult); LOG.i("pq", "seekResult2:" + seekResult2); player1.seekTo(seekResult); player2.seekTo(seekResult2); } private int countAccompanyPosition(int recordPosition) { int currentOffsetValue = mSettingFragment.getCurrentOffsetValue(); LOG.i("pq", "currentOffsetValue:" + currentOffsetValue); int exceptPosition = recordPosition + currentOffsetValue; return exceptPosition; } private void initPlayer() { player1 = new CustomPlayer("luzhi"); player2 = new CustomPlayer("伴奏"); player1.setOnEventListener(new CustomPlayer.OnEventListener() { @Override public void onProgress(int progress) { if (!checkActivityExist()) { return; } toShowDelay(); String s = TimeUtils.msToTime(progress); viewBinding.tvCurrentProgress.setText(s); int maxProgress = viewBinding.seekPlay.getMax(); int percent = (int) ((progress * 1.0f / player1.getTotal()) * maxProgress); viewBinding.seekPlay.setProgress(percent); } @Override public void onPrepared(int duration) { if (!checkActivityExist()) { return; } firstPlayDuration = duration; String s = TimeUtils.msToTime(duration); viewBinding.tvTotalProgress.setText(s); toRealPlay(); } @Override public void onCompleted() { if (!checkActivityExist()) { return; } viewBinding.seekPlay.setProgress(0); viewBinding.seekPlay2.setProgress(0); player2.pause(); handleSeekEvent(); updatePlayStatus(); } @Override public void onError() { } @Override public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { MusicHandleActivity.this.videoWidth = width; MusicHandleActivity.this.videoHeight = height; resetVideoSize(width, height); } }); player2.setOnEventListener(new CustomPlayer.OnEventListener() { @Override public void onProgress(int progress) { String s = TimeUtils.msToTime(progress); viewBinding.tvCurrentProgress2.setText(s); int maxProgress = viewBinding.seekPlay2.getMax(); int percent = (int) ((progress * 1.0f / player2.getTotal()) * maxProgress); viewBinding.seekPlay2.setProgress(percent); } @Override public void onPrepared(int duration) { secondPlayDuration = duration; String s = TimeUtils.msToTime(duration); viewBinding.tvTotalProgress2.setText(s); toRealPlay(); } @Override public void onCompleted() { } @Override public void onError() { } @Override public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { } }); } private void toShowDelay() { int cu = player1.getCu(); int cu1 = player2.getCu(); int dif = cu1 - cu; String text = "演奏进度:" + cu + "\n伴奏进度:" + cu1 + "\n差值:" + dif; viewBinding.tvDelayText.setText(text); if (!player1.isPlaying()) { return; } LOG.i("pq", "dif:" + dif); int expectDelay = dif - mSettingFragment.getCurrentOffsetValue(); LOG.i("pq", "expectDelay:" + expectDelay); int difAbs = Math.abs(expectDelay); if (difAbs > MAX_ADJUSTMENT) { float s = difAbs / 1000f; if (expectDelay > 0) { player1.setSpeed(1.0f + s); player2.setSpeed(1.0f - s); } else { player1.setSpeed(1.0f - s); player2.setSpeed(1.0f + s); } } else { player1.setSpeed(1.0f); player2.setSpeed(1.0f); } } private void toRealPlay() { if (firstPlayDuration != 0 && secondPlayDuration != 0) { player1.resetToPrepare(); player2.resetToPrepare(); player1.start(); player2.start(); setVolume(); updatePlayStatus(); } } private void setVolume() { if (mSettingFragment != null) { float originalVolume = mSettingFragment.getOriginalVolume(); float accompanyVolume = mSettingFragment.getAccompanyVolume(); player1.setVolume(originalVolume); player2.setVolume(accompanyVolume); } } private void resetVideoSize(int width, int height) { int surfaceWidth = viewBinding.flSurface.getWidth(); int surfaceHeight = viewBinding.flSurface.getHeight(); LOG.i("resetVideoSize", "surfaceWidth:" + surfaceWidth); LOG.i("resetVideoSize", "surfaceHeight:" + surfaceHeight); float containerAspectRatio = surfaceWidth * 1.0f / surfaceHeight; float videoAspectRatio = width * 1.0f / height; LOG.i("resetVideoSize", "containerAspectRatio:" + containerAspectRatio); LOG.i("resetVideoSize", "videoAspectRatio:" + videoAspectRatio); boolean b = NumberUtils.compareResult(containerAspectRatio, videoAspectRatio); LOG.i("resetVideoSize", "compareResult:" + b); if (b) { return; } LOG.i("resetVideoSize", "videoWidth:" + width); LOG.i("resetVideoSize", "videoHeight:" + height); int w; int h; if (containerAspectRatio > videoAspectRatio) { // 容器更宽,视频高度适应容器高度 h = surfaceHeight; w = (int) (surfaceHeight * videoAspectRatio); } else { // 容器更高,视频宽度适应容器宽度 w = surfaceWidth; h = (int) (surfaceWidth / videoAspectRatio); } LOG.i("resetVideoSize", "w:" + w); LOG.i("resetVideoSize", "h:" + h); if (w > surfaceWidth) { w = surfaceWidth; } if (h > surfaceHeight) { h = surfaceHeight; } LOG.i("pq", "w:" + w); LOG.i("pq", "h:" + h); FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) mSurfaceView.getLayoutParams(); layoutParams.width = w; layoutParams.height = h; mSurfaceView.setLayoutParams(layoutParams); // mSurfaceView.getHolder().setFixedSize(w, h); } private boolean checkRecordFile() { if (TextUtils.isEmpty(recordFilePath)) { return false; } File file = new File(recordFilePath); if (!file.exists()) { return false; } return true; } private void toPlay(String accompanyPath) { player1.play(recordFilePath); player2.play(accompanyPath); } private boolean checkRecordFile(String recordUrl) { String fileEndSuffix = MyFileUtils.getWAVOrMp4FileSuffix(recordUrl); String recordFileDownloadPath = getRecordFileDownloadPath(recordUrl, fileEndSuffix); recordFilePath = recordFileDownloadPath; Log.i("pq", "checkRecordFile:" + recordFilePath); File file = new File(recordFileDownloadPath); if (file.exists()) { return true; } boolean validDownloadUrl = UrlUtils.isValidDownloadUrl(recordUrl); if (!validDownloadUrl) { ToastUtil.getInstance().showShort("未找到演奏文件,请退出重试"); return false; } Log.i("pq", "下载草稿"); setLoadingCancelable(false); showLoading("草稿下载中"); MixHelper.getInstance().download(recordUrl, fileEndSuffix, new ResultCallback() { @Override public void onSuccess(String s) { if (!checkActivityExist()) { return; } runOnUiThread(new Runnable() { @Override public void run() { hideLoading(); preLoad(); } }); } @Override public void onProgress(int progressPercent) { if (!checkActivityExist()) { return; } runOnUiThread(new Runnable() { @Override public void run() { updateLoadingText("草稿下载中" + progressPercent + "%"); } }); } @Override public void onFail(int errorCode, String errorStr) { if (!checkActivityExist()) { return; } runOnUiThread(new Runnable() { @Override public void run() { ToastUtil.getInstance().showShort("草稿下载失败,请重试"); hideLoading(); } }); } }); return false; } private boolean checkAccompanimentMp3File() { if (TextUtils.isEmpty(accompanyUrl)) { ToastUtil.getInstance().showShort("未找到伴奏文件,请退出重试"); return false; } String accompanyPath = getAccompanyPath(); File file = new File(accompanyPath); if (file.exists()) { return true; } boolean validDownloadUrl = UrlUtils.isValidDownloadUrl(accompanyUrl); if (!validDownloadUrl) { ToastUtil.getInstance().showShort("未找到伴奏文件,请退出重试"); return false; } setLoadingCancelable(false); showLoading("伴奏下载中"); MixHelper.getInstance().download(accompanyUrl, MyFileUtils.MP3_FILE_SUFFIX, new ResultCallback() { @Override public void onSuccess(String s) { if (!checkActivityExist()) { return; } runOnUiThread(new Runnable() { @Override public void run() { preparePlay(); hideLoading(); } }); } @Override public void onProgress(int progressPercent) { if (!checkActivityExist()) { return; } runOnUiThread(new Runnable() { @Override public void run() { updateLoadingText("伴奏下载中" + progressPercent + "%"); } }); } @Override public void onFail(int errorCode, String errorStr) { if (!checkActivityExist()) { return; } runOnUiThread(new Runnable() { @Override public void run() { ToastUtil.getInstance().showShort("伴奏下载失败,请重试"); hideLoading(); } }); } }); return false; } @Override public void hideLoading() { setLoadingCancelable(true); toSetLoadingCancelable(true); if (mLoadingTipDialog != null) { mLoadingTipDialog.hide(); } super.hideLoading(); } private String getAccompanyPath() { String accompanyPath = MixHelper.getInstance().getDownloadSavePath(accompanyUrl, MyFileUtils.MP3_FILE_SUFFIX); return accompanyPath; } private String getRecordFileDownloadPath(String recordFileUrl, String fileEndSuffix) { String recordFilePath; if (MyFileUtils.isVideoFromUrl(recordFileUrl)) { recordFilePath = MixHelper.getInstance().getDownloadSavePathForMp4(recordFileUrl); } else { recordFilePath = MixHelper.getInstance().getDownloadSavePath(recordFileUrl, fileEndSuffix); } return recordFilePath; } @Override protected AcMusicHandleLayoutBinding getLayoutView() { return AcMusicHandleLayoutBinding.inflate(getLayoutInflater()); } @Override public void onClick(View v) { int id = v.getId(); if (id == R.id.iv_play) { if (player1.isPlaying()) { pausePlay(); } else { player1.resume(); player2.resume(); updatePlayStatus(); } return; } if (id == R.id.iv_unfold_sentting) { handleSettingVisibility(); return; } if (id == R.id.iv_back) { checkTipToFinish(); return; } } @Override protected void onStop() { super.onStop(); pausePlay(); } private void pausePlay() { if (player1.isPlaying()) { player1.pause(); player2.pause(); //暂停的时候需要校准一次,防止定时器触发 aligningAccompany(mSettingFragment.getCurrentOffsetValue()); } updatePlayStatus(); } private void checkTipToFinish() { boolean hasUpdate = mViewModel.isHasUpdate(); if (hasUpdate) { showSaveTipDialog(); } else { finish(); } } private void showSaveTipDialog() { CommonConfirmDialog2 commonConfirmDialog = new CommonConfirmDialog2(this); commonConfirmDialog.setWidth(SizeUtils.dp2px(387)); commonConfirmDialog.show(); commonConfirmDialog.setTitle("提示"); commonConfirmDialog.setContent("是否将本次录制的作品保存为草稿?"); commonConfirmDialog.setOnConfirmClickListener(new View.OnClickListener() { @Override public void onClick(View v) { commonConfirmDialog.dismiss(); isNeedFinishPage = true; toSaveDraft(); } }); commonConfirmDialog.setOnCancelClickListener(new View.OnClickListener() { @Override public void onClick(View v) { commonConfirmDialog.dismiss(); finish(); } }); } /** * 监听返回键 * * @param keyCode * @param event * @return */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { checkTipToFinish(); return true; } return super.onKeyDown(keyCode, event); } private void handleSettingVisibility() { int visibility = viewBinding.flSetting.getVisibility(); if (visibility == View.VISIBLE) { viewBinding.groupSetting.setVisibility(View.GONE); viewBinding.ivUnfoldSentting.setVisibility(View.VISIBLE); } else { viewBinding.groupSetting.setVisibility(View.VISIBLE); viewBinding.ivUnfoldSentting.setVisibility(View.GONE); } mHandler.postDelayed(new Runnable() { @Override public void run() { resetVideoSize(videoWidth, videoHeight); } }, 50); } private void updatePlayStatus() { if (player1.isPlaying()) { viewBinding.ivPlayPointer.setRotation(0); handleAnim(true); viewBinding.ivPlay.setImageResource(isVideo ? R.drawable.icon_music_merge_pause_white : R.drawable.icon_music_merge_pause); } else { handleAnim(false); viewBinding.ivPlayPointer.setRotation(92); viewBinding.ivPlay.setImageResource(isVideo ? R.drawable.icon_music_merge_play_white : R.drawable.icon_music_merge_play); } } private void handleAnim(boolean isPlay) { if (isVideo) { return; } if (player1 != null && player1.getPlayer() != null && isPlay) { viewBinding.musicFrequencyView.setMediaPlayer(player1.getPlayer()); } rotation(isPlay); rotationAlbum(isPlay); } private void rotation(boolean isPlay) { float from = isPlay ? 92 : 0; float to = isPlay ? 0 : 92; viewBinding.ivPlayPointer.clearAnimation(); float rotation = viewBinding.ivPlayPointer.getRotation(); LOG.i("rotation:" + rotation); if (mRotateAnimation == null) { mRotateAnimation = ObjectAnimator.ofFloat(viewBinding.ivPlayPointer, "rotation", from, to); mRotateAnimation.setInterpolator(new LinearInterpolator());//不停顿 mRotateAnimation.setDuration(300); mRotateAnimation.setRepeatCount(0); } mRotateAnimation.setFloatValues(from, to); mRotateAnimation.start(); } private void rotationAlbum(boolean isPlay) { float rotation = viewBinding.flAblum.getRotation(); if (mAlbumRotationAnimator == null) { mAlbumRotationAnimator = ObjectAnimator.ofFloat(viewBinding.flAblum, "rotation", 0f, 360f); mAlbumRotationAnimator.setDuration(5000); // 设置动画持续时间为1秒 mAlbumRotationAnimator.setRepeatCount(ObjectAnimator.INFINITE); // 设置无限循环 mAlbumRotationAnimator.setInterpolator(new LinearInterpolator()); // 设置动画插值器,这里使用线性插值器 } if (isPlay) { if (mAlbumRotationAnimator.isPaused()) { mAlbumRotationAnimator.resume(); } else { mAlbumRotationAnimator.start(); // 启动动画 } } else { mAlbumRotationAnimator.pause();// } } @Override public void saveWorksSuccess(Object data, String des,String imgCover) { if (!checkActivityExist()) { return; } currentStep = 2; // showToastViewAndFinish("发布成功", true); String worksId = null; if (data instanceof String) { worksId = (String) data; } if (!TextUtils.isEmpty(worksId)) { ShareIntentBean shareIntentBean = buildShareData(worksId, des,imgCover); toShowShareDialog(shareIntentBean, true); } else { showToastViewAndFinish(getString(R.string.publish_success), true); } } private ShareIntentBean buildShareData(String worksId,String shareDes,String imgCover){ ShareIntentBean bean = new ShareIntentBean(); String url = String.format(WebConstants.MY_WORKS_SHARE, worksId); bean.setLinkUrl(url); bean.setTitle(getString(R.string.share_works_title)); bean.setDes(shareDes); bean.setThumb(imgCover); return bean; } private void toShowShareDialog(ShareIntentBean intentBean, boolean isReCallBack) { toUpdateLoadingText(getCurrentProgress(100), getString(R.string.publish_success)); mHandler.postDelayed(new Runnable() { @Override public void run() { hideLoading(); showShareDialog(intentBean, isReCallBack); } }, 1500); } private void showShareDialog(ShareIntentBean intentBean, boolean isReCallBack) { ShareDialog shareDialog = new ShareDialog(this); shareDialog.setOnEventListener(new ShareDialog.OnEventListener() { @Override public void toShare(ShareType shareType) { goShare(intentBean, shareType); } }); shareDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { @Override public void onDismiss(DialogInterface dialog) { toFinish(isReCallBack); } }); shareDialog.show(); } private void goShare(ShareIntentBean intentBean, ShareType shareType) { if (shareType == ShareType.COPY_LINK) { ClipboardUtils.copyText(intentBean.getLinkUrl()); ToastUtil.getInstance().showShort("复制成功"); return; } else if (shareType == ShareType.WEIXIN) { intentBean.setShare_media(SHARE_MEDIA.WEIXIN); } else if (shareType == ShareType.WEIXIN_CIRCLE) { intentBean.setShare_media(SHARE_MEDIA.WEIXIN_CIRCLE); } if (intentBean.getShare_media() != null) { CommonShareHelper.toShareUrl(MusicHandleActivity.this, intentBean, this); } } private void toFinish(boolean isReCallBack) { Intent intent = new Intent(); if (isReCallBack) { intent.putExtra("saveWorksStatus", 1); } setResult(RESULT_OK, intent); finish(); } @Override public void getDetailSuccess(MusicDataBean data) { if (!checkActivityExist()) { return; } if (data != null) { this.originalFileUrl = data.getVideoUrl(); String jsonConfig = data.getJsonConfig(); accompanyUrl = data.getAccompanyUrl(); if (mSettingFragment != null) { if (!TextUtils.isEmpty(jsonConfig)) { toApplyConfig(jsonConfig); } mSettingFragment.setAccompanyUrl(accompanyUrl); } //这里为了兼容IOS录制的wav音频文件格式不正确 导致合成失败的问题Failed to read frame size: Could not seek to 1026. //取服务端存储的文件 boolean isVideo = MyFileUtils.isVideoFromUrl(data.getVideoUrl()); String fileUrl = isVideo ? data.getVideoUrl() : data.getRecordFilePath(); boolean b = checkRecordFile(fileUrl); if (b) { preLoad(); } } } private void toApplyConfig(String jsonConfig) { try { MusicMergeConfigBean musicMergeConfigBean = GsonUtils.fromJson(jsonConfig, MusicMergeConfigBean.class); defaultDelay = musicMergeConfigBean.getDefaultDelay(); evaluateDelay = musicMergeConfigBean.getEvaluateDelay(); mSettingFragment.applyConfig(musicMergeConfigBean); } catch (Exception e) { e.printStackTrace(); } } @Override public void saveWorksDraftSuccess() { if (!checkActivityExist()) { return; } currentStep = 1; mViewModel.getUpdateEvent().setValue(false); if (isNeedFinishPage) { showToastViewAndFinish("保存成功", false); } else { toUpdateLoadingText(getCurrentProgress(100), "保存成功"); mHandler.postDelayed(new Runnable() { @Override public void run() { hideLoading(); if (isNeedTip()) { showOtherTipDialog(); } } }, 500); } } private boolean isNeedTip() { //云教练进来的需要提示 作品草稿过来的不需要 return TextUtils.isEmpty(worksId); } private void showOtherTipDialog() { CommonConfirmDialog2 commonConfirmDialog = new CommonConfirmDialog2(this); commonConfirmDialog.setWidth(SizeUtils.dp2px(387)); commonConfirmDialog.show(); commonConfirmDialog.setTitle("提示"); commonConfirmDialog.setContent("已成功保存到草稿,草稿7天未发布\n将自动删除。"); commonConfirmDialog.setCancelText("确认"); commonConfirmDialog.setConfirmText("查看草稿"); commonConfirmDialog.setOnCancelClickListener(new View.OnClickListener() { @Override public void onClick(View v) { commonConfirmDialog.dismiss(); } }); commonConfirmDialog.setOnConfirmClickListener(new View.OnClickListener() { @Override public void onClick(View v) { commonConfirmDialog.dismiss(); //从首页个人中心跳转我的作品 JumpUtils.jumpMain(4); goMyWorks(); } }); } private void goMyWorks() { ARouter.getInstance().build(RouterPath.Homework.MY_WORK) .withInt(Constants.MAIN_PAGE_SELECT_POTION_KEY, 1) .navigation(); finish(); } private void showToastViewAndFinish(String tip, boolean isReCallBack) { //测试lyr提出提示要在当前面提示,所以给出延迟finish // viewBinding.tvToastView.setText(tip); // viewBinding.tvToastView.setVisibility(View.VISIBLE); toUpdateLoadingText(getCurrentProgress(100), tip); mHandler.postDelayed(new Runnable() { @Override public void run() { hideLoading(); toFinish(isReCallBack); } }, 1500); } @Override public void upLoadImageSuccess(String url, boolean isVideoCover) { if (!checkActivityExist()) { return; } if (mViewModel != null) { if (isVideoCover) { mViewModel.refreshMusicVideoCover(url); } else { mViewModel.refreshMusicWorksCover(url); } } } private void refreshMusicInfoPreCover(String imgCover) { mViewModel.refreshMusicPreCover(imgCover); } private void refreshMusicInfoVideoCover(String imgCover) { mViewModel.refreshMusicVideoCover(imgCover); } private void refreshMusicInfo(String imgCover) { MusicInfoBean bean = new MusicInfoBean(); bean.setCover(imgCover); bean.setMusicTitle(mTitle); mViewModel.getMusicInfoLiveData().setValue(bean); } private int getCurrentProgress(int progress) { float singleStepMaxProgress = MAX_PROGRESS * 1.0f / MAX_STEP; float progressPercent = progress * 1.0f / 100; int result = (int) (singleStepMaxProgress * currentStep + singleStepMaxProgress * progressPercent); LOG.i("progress:" + progress + "--currentStep:" + currentStep + "--currentStepProgress" + singleStepMaxProgress * currentStep + "--progressPercent:" + progressPercent + "--result:" + result); return result; } @Override public void upLoadImageFailure() { ToastUtil.getInstance().showShort("封面上传失败"); } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); UMShareAPI.get(MusicHandleActivity.this).onActivityResult(requestCode, resultCode, data); if (resultCode == RESULT_OK) { if (requestCode == REQUEST_CODE_LOCAL || requestCode == REQUEST_CODE_LOCAL_VIDEO_COVER) { if (data != null) { // 图片、视频、音频选择结果回调 List selectList = PictureSelector.obtainMultipleResult(data); String v_path = null; if (selectList != null && selectList.size() > 0) { v_path = selectList.get(0).getCompressPath(); } if (!TextUtils.isEmpty(v_path)) { boolean isImg = MyFileUtils.isImg(v_path); if (isImg) { if (requestCode == REQUEST_CODE_LOCAL_VIDEO_COVER) { refreshMusicInfoVideoCover(v_path); } else { refreshMusicInfoPreCover(v_path); } } else { ToastUtil.getInstance().showShort("请选择图片类型文件"); } } } } if (requestCode == REQUEST_CODE_VIDEO_COVER) { if (data != null) { String imgPath = data.getStringExtra(Constants.COMMON_EXTRA_KEY); refreshMusicInfoVideoCover(imgPath); return; } } } } private void toShowLoading(int progress, String text) { if (mLoadingTipDialog != null) { mLoadingTipDialog.showLoading(progress, text); } } private void toSetLoadingCancelable(boolean flag) { if (mLoadingTipDialog != null) { mLoadingTipDialog.setLoadingCancelable(flag); } } private void toUpdateLoadingText(int progress, String text) { if (mLoadingTipDialog != null) { mLoadingTipDialog.updateLoadingText(progress, text); } } private void initLoadingDialog() { if (mLoadingTipDialog == null) { mLoadingTipDialog = new MergeLoadingTipDialog(this); } } @Override public void onDestroy() { releaseAnim(); super.onDestroy(); UMShareAPI.get(MusicHandleActivity.this).release(); if (mHandler != null) { mHandler.removeCallbacksAndMessages(null); } if (mSurfaceView != null && mSurfaceView.getSurfaceTexture() != null) { mSurfaceView.getSurfaceTexture().release(); } if (player1 != null) { player1.release(); } if (player2 != null) { player2.release(); } } private void releaseAnim() { if (viewBinding != null && viewBinding.musicFrequencyView != null) { viewBinding.musicFrequencyView.release(); } if (mRotateAnimation != null) { mRotateAnimation.cancel(); mRotateAnimation = null; } if (mAlbumRotationAnimator != null) { mAlbumRotationAnimator.cancel(); mAlbumRotationAnimator = null; } } @Override public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) { if (mSurfaceTexture == null) { mSurfaceTexture = surface; } else { mSurfaceView.setSurfaceTexture(mSurfaceTexture); } if (player1 != null) { toPlay(getAccompanyPath()); player1.setSurface(new Surface(mSurfaceTexture)); } } @Override public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) { } @Override public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) { return false; } @Override public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) { } @Override public void finish() { //为了适配华为mata40曲面屏,此页面是横屏,前一页面是竖屏,返回回去的时候会有UI闪动,所以这样处理 //观察发现横屏模式时候没有达到曲面最大效果(竖屏可以达到),猜测横屏模式就不是曲面模式了,这个时候回到前面(竖屏)页面,屏幕的最外层的容器可能会变化导致UI闪动 checkScreenOrientation(); super.finish(); } @Override public void onBackPressed() { //为了适配华为mata40曲面屏,此页面是横屏,前一页面是竖屏,返回回去的时候会有UI闪动,所以这样处理 //观察发现横屏模式时候没有达到曲面最大效果(竖屏可以达到),猜测横屏模式就不是曲面模式了,这个时候回到前面(竖屏)页面,屏幕的最外层的容器可能会变化导致UI闪动 checkScreenOrientation(); super.onBackPressed(); } private void checkScreenOrientation() { LOG.i("isNeedResetScreenOrientation:" + isNeedResetScreenOrientation); if (isNeedResetScreenOrientation) { if (getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } } } @Override public void onStart(SHARE_MEDIA shareMedia) { } @Override public void onResult(SHARE_MEDIA shareMedia) { ToastUtil.getInstance().showShort("分享成功啦"); } @Override public void onError(SHARE_MEDIA shareMedia, Throwable throwable) { ToastUtil.getInstance().showShort("分享失败啦"); } @Override public void onCancel(SHARE_MEDIA shareMedia) { ToastUtil.getInstance().showShort("分享取消了"); } }