diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 66fa088..82e83c1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -24,37 +24,44 @@ android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" - android:icon="@mipmap/ic_launcher" + android:icon="@mipmap/logo" android:label="@string/app_name" - android:roundIcon="@mipmap/ic_launcher_round" + android:roundIcon="@mipmap/logo" android:supportsRtl="true" android:theme="@style/Theme.RecordScreen" tools:targetApi="31"> - - - + android:exported="true" > + + + + + + + android:exported="false"> @@ -66,11 +73,19 @@ + android:screenOrientation="portrait" + android:taskAffinity="" + android:theme="@style/Theme.Transparent" /> + (), ConnectionListener,F private fun bingVp() { val tabIcons = - intArrayOf(R.drawable.tab1_selector, R.drawable.tab2_selector, R.drawable.tab3_selector) + intArrayOf(R.drawable.tab1_selector, R.drawable.tab2_selector) binding.run { viewPager2.isUserInputEnabled = false viewPager2.adapter = ViewPager2Adapter(this@MainActivity1) @@ -155,11 +155,8 @@ class MainActivity1 : BaseActivity(), ConnectionListener,F override fun onTabReselected(tab: TabLayout.Tab?) { } - }) - } - } private fun showPermissionDialog() { @@ -213,28 +210,18 @@ class MainActivity1 : BaseActivity(), ConnectionListener,F this@MainActivity1.moveTaskToBack(true) } - - override fun onServiceConnected() { - viewModel.updateServiceConnectStatus(true) - FloatingWindowBridge.registerCallback(this) -// updateFloatingBtnStatus() - - //新开进程的时候检测当前悬浮窗状态,刷新当前各ImageView状态 - FloatingWindowBridge.sendCommand(FloatingWindowBridge.COMMEND_sync_view_status) - - } - /** - * 新开进程的时候检测当前悬浮窗状态,刷新当前各ImageView状态 - */ - private fun updateFloatingBtnStatus(){ - FloatingWindowBridge.sendCommand(FloatingWindowBridge.COMMEND_sync_view_status) - } - override fun onResume() { super.onResume() //初始进程中,在桌面回到Activity的时候更新当前录制状态 FloatingWindowBridge.sendCommand(FloatingWindowBridge.COMMEND_sync_recording_status) } + override fun onServiceConnected() { + viewModel.updateServiceConnectStatus(true) + FloatingWindowBridge.registerCallback(this) + //新开进程的时候检测当前悬浮窗状态,刷新当前各ImageView状态 + FloatingWindowBridge.sendCommand(FloatingWindowBridge.COMMEND_sync_view_status) + FloatingWindowBridge.sendCommand(FloatingWindowBridge.COMMEND_sync_recording_status) + } override fun onRefreshViewShow( webCamShow: Boolean, diff --git a/app/src/main/java/com/audio/record/screen/test/activity/ScreenshotAnimActivity.kt b/app/src/main/java/com/audio/record/screen/test/activity/ScreenshotAnimActivity.kt new file mode 100644 index 0000000..0e33e81 --- /dev/null +++ b/app/src/main/java/com/audio/record/screen/test/activity/ScreenshotAnimActivity.kt @@ -0,0 +1,110 @@ +package com.audio.record.screen.test.activity + +import android.animation.Animator +import android.animation.AnimatorSet +import android.animation.ObjectAnimator +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.media.projection.MediaProjectionManager +import android.os.Bundle +import android.os.Handler +import android.os.Looper +import android.os.PersistableBundle +import android.view.animation.DecelerateInterpolator +import android.widget.ImageView +import android.widget.TextView +import androidx.activity.result.ActivityResultLauncher +import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isVisible +import com.audio.record.screen.test.R +import com.audio.record.screen.test.base.BaseActivity +import com.audio.record.screen.test.databinding.ActivityPlayBinding +import com.audio.record.screen.test.service.FloatingCallback +import com.audio.record.screen.test.service.FloatingWindowBridge +import com.audio.record.screen.test.service.ScreenshotAnimExecutor +import com.audio.record.screen.test.tool.Common +import com.audio.record.screen.test.tool.ScreenCaptureHelper + + +/** + * Service悬浮窗中请求权限的透明Activity + */ +class ScreenshotAnimActivity : AppCompatActivity(), FloatingCallback { + + + private lateinit var imageView: ImageView + private lateinit var tv: TextView + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + Common.setStatusBarTextColor(this, true) + setContentView(R.layout.floating_screenshot_anim) + Common.showLog("---ScreenshotAnimActivity--onCreate") + FloatingWindowBridge.registerCallback(this) + imageView = findViewById(R.id.image) + tv = findViewById(R.id.tv_content) + } + + + override fun onRefreshBitmap(bitmap: Bitmap) { + super.onRefreshBitmap(bitmap) + Common.showLog("---ScreenshotAnimActivity--onRefreshBitmap") + tv.isVisible = false + imageView.setImageBitmap(bitmap) + + val fullScreenSize = Common.getFullScreenSize(this) + val screenWidth = fullScreenSize.first + val screenHeight = fullScreenSize.second + + val scale = 0.25f + val targetX = (screenWidth - screenWidth * scale - 12).toFloat() + val targetY = (screenHeight - screenHeight * scale - 14).toFloat() + + // 设置初始位置在中心 + imageView.translationX = 0f + imageView.translationY = 0f + imageView.scaleX = 1f + imageView.scaleY = 1f + + // 缩放动画 + val scaleX = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, scale) + val scaleY = ObjectAnimator.ofFloat(imageView, "scaleY", 1f, scale) + + // 位移动画(目标点是右下角) + val translateX = ObjectAnimator.ofFloat(imageView, "translationX", 0f, targetX - screenWidth / 2f) + val translateY = ObjectAnimator.ofFloat(imageView, "translationY", 0f, targetY - screenHeight / 2f) + + val animatorSet = AnimatorSet().apply { + playTogether(scaleX, scaleY, translateX, translateY) + duration = 600L + interpolator = DecelerateInterpolator() + addListener(object : Animator.AnimatorListener { + override fun onAnimationStart(animation: Animator) { + Common.showLog("-----动画开始") + } + + override fun onAnimationEnd(animation: Animator) { + Common.showLog("-----动画结束") + Handler(Looper.getMainLooper()).postDelayed({ + finish() + }, 2000) + } + + override fun onAnimationCancel(animation: Animator) {} + override fun onAnimationRepeat(animation: Animator) {} + }) + } + animatorSet.start() + + + + } + + override fun onResume() { + super.onResume() + Common.showLog("--ScreenshotAnimActivity---onResume") + } + + +} \ No newline at end of file diff --git a/app/src/main/java/com/audio/record/screen/test/activity/WelcomeActivity.kt b/app/src/main/java/com/audio/record/screen/test/activity/WelcomeActivity.kt new file mode 100644 index 0000000..6c59bad --- /dev/null +++ b/app/src/main/java/com/audio/record/screen/test/activity/WelcomeActivity.kt @@ -0,0 +1,48 @@ +package com.audio.record.screen.test.activity + +import android.content.Intent +import androidx.appcompat.app.AppCompatActivity +import android.os.Bundle +import android.os.CountDownTimer +import com.audio.record.screen.test.R +import com.audio.record.screen.test.base.BaseActivity +import com.audio.record.screen.test.databinding.ActivityWelcomeBinding + +class WelcomeActivity : BaseActivity() { + private val total = 2000L + private var countDownTimer:CountDownTimer? = null + override fun initBinding(): ActivityWelcomeBinding = + ActivityWelcomeBinding.inflate(layoutInflater) + + override fun getFullColor(): Boolean = true + + override fun onCreateInit() { + countDownTimer =object :CountDownTimer(total, 1000){ + override fun onTick(millisUntilFinished: Long) { + + } + + override fun onFinish() { + toMain() + } + + } + countDownTimer?.start() + + } + + private fun toMain(){ + startActivity(Intent(this,MainActivity1::class.java)) + finish() + } + + override fun onInitPadding(): Boolean = false + + + override fun onDestroy() { + super.onDestroy() + countDownTimer?.cancel() + countDownTimer = null + + } +} \ No newline at end of file diff --git a/app/src/main/java/com/audio/record/screen/test/adapter/ImageGroupAdapter.kt b/app/src/main/java/com/audio/record/screen/test/adapter/ImageGroupAdapter.kt index 7e85423..2f13a00 100644 --- a/app/src/main/java/com/audio/record/screen/test/adapter/ImageGroupAdapter.kt +++ b/app/src/main/java/com/audio/record/screen/test/adapter/ImageGroupAdapter.kt @@ -32,9 +32,18 @@ class ImageGroupAdapter(context: Context, private var click: (cropRatio: String) adapter = ImageInfoAdapter(mContext, position == 0) {}.apply { updateData(item.images) } - layoutManager = GridLayoutManager(mContext, 3) + if (this.layoutManager == null) { + layoutManager = GridLayoutManager(mContext, 3) + } isNestedScrollingEnabled = false - addItemDecoration(GridSpacingItemDecoration(3, 5.dpToPx(mContext), true)) + setHasFixedSize(false) + if (this.itemDecorationCount <= 0) { + val gridSpacingItemDecoration = + GridSpacingItemDecoration(3, 5.dpToPx(mContext), true) + addItemDecoration(gridSpacingItemDecoration) + } + + } } } diff --git a/app/src/main/java/com/audio/record/screen/test/adapter/VideoGroupAdapter.kt b/app/src/main/java/com/audio/record/screen/test/adapter/VideoGroupAdapter.kt index 2c9abb1..0d7527e 100644 --- a/app/src/main/java/com/audio/record/screen/test/adapter/VideoGroupAdapter.kt +++ b/app/src/main/java/com/audio/record/screen/test/adapter/VideoGroupAdapter.kt @@ -7,24 +7,27 @@ import androidx.recyclerview.widget.RecyclerView import com.audio.record.screen.test.base.BaseAdapter import com.audio.record.screen.test.data.VideoGroup import com.audio.record.screen.test.databinding.AdapterVideoDateBinding +import com.audio.record.screen.test.tool.Common import com.audio.record.screen.test.tool.NoScrollLinearLayoutManager -class VideoGroupAdapter(context: Context, private var click: (cropRatio:String) -> Unit) : +class VideoGroupAdapter(context: Context, private var click: (cropRatio: String) -> Unit) : BaseAdapter(context) { override fun getViewBinding(parent: ViewGroup?): AdapterVideoDateBinding { return AdapterVideoDateBinding.inflate(LayoutInflater.from(parent!!.context), parent, false) } override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - val itemHolder: VHolder = holder as VHolder + val itemHolder: VHolder = + holder as VHolder val item = data[position] itemHolder.vb.run { - tvDate.text = item.date + tvDate.text = item.date videoInfoRecycler.run { - adapter = VideoInfoAdapter(mContext){}.apply { + setHasFixedSize(false) + adapter = VideoInfoAdapter(mContext, position == data.size - 1) {}.apply { updateData(item.videos) } layoutManager = NoScrollLinearLayoutManager(mContext) @@ -33,7 +36,6 @@ class VideoGroupAdapter(context: Context, private var click: (cropRatio:String) } - } } \ No newline at end of file diff --git a/app/src/main/java/com/audio/record/screen/test/adapter/VideoInfoAdapter.kt b/app/src/main/java/com/audio/record/screen/test/adapter/VideoInfoAdapter.kt index f55b64d..06471c2 100644 --- a/app/src/main/java/com/audio/record/screen/test/adapter/VideoInfoAdapter.kt +++ b/app/src/main/java/com/audio/record/screen/test/adapter/VideoInfoAdapter.kt @@ -4,6 +4,7 @@ import android.content.Context import android.content.Intent import android.view.LayoutInflater import android.view.ViewGroup +import androidx.core.view.isVisible import androidx.recyclerview.widget.RecyclerView import com.audio.record.screen.test.activity.PlayActivity import com.audio.record.screen.test.base.BaseAdapter @@ -11,7 +12,11 @@ import com.audio.record.screen.test.data.VideoInfo import com.audio.record.screen.test.databinding.AdapterVideoInfoBinding import com.audio.record.screen.test.tool.Common -class VideoInfoAdapter(context: Context, private var click: (cropRatio: String) -> Unit) : +class VideoInfoAdapter( + context: Context, + var isLast: Boolean, + private var click: (cropRatio: String) -> Unit +) : BaseAdapter(context) { override fun getViewBinding(parent: ViewGroup?): AdapterVideoInfoBinding { return AdapterVideoInfoBinding.inflate(LayoutInflater.from(parent!!.context), parent, false) @@ -22,15 +27,17 @@ class VideoInfoAdapter(context: Context, private var click: (cropRatio: String) holder as VHolder val item = data[position] + itemHolder.vb.run { + space.isVisible = position == data.size - 1 && isLast image.setImageBitmap(item.thumbnail) tvName.text = item.displayName tvTime.text = Common.formatDuration(item.duration) tvSize.text = Common.formatFileSize(item.size) root.setOnClickListener { - mContext.startActivity(Intent(mContext,PlayActivity::class.java).apply { + mContext.startActivity(Intent(mContext, PlayActivity::class.java).apply { putExtra(PlayActivity.KEY_URI, item.uri) - putExtra(PlayActivity.KEY_name,item.displayName) + putExtra(PlayActivity.KEY_name, item.displayName) }) } } diff --git a/app/src/main/java/com/audio/record/screen/test/adapter/ViewPager2Adapter.kt b/app/src/main/java/com/audio/record/screen/test/adapter/ViewPager2Adapter.kt index e48fa28..15aaa16 100644 --- a/app/src/main/java/com/audio/record/screen/test/adapter/ViewPager2Adapter.kt +++ b/app/src/main/java/com/audio/record/screen/test/adapter/ViewPager2Adapter.kt @@ -11,8 +11,7 @@ class ViewPager2Adapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) { private val fragments: List = arrayListOf( MainFragment.newInstance(), - RecordMainFragment.newInstance(), - MainFragment.newInstance() + RecordMainFragment.newInstance() ) override fun getItemCount(): Int = fragments.size diff --git a/app/src/main/java/com/audio/record/screen/test/dialog/DialogPermission.kt b/app/src/main/java/com/audio/record/screen/test/dialog/DialogPermission.kt index d5992d2..d8f230c 100644 --- a/app/src/main/java/com/audio/record/screen/test/dialog/DialogPermission.kt +++ b/app/src/main/java/com/audio/record/screen/test/dialog/DialogPermission.kt @@ -27,7 +27,7 @@ class DialogPermission(private var mClickType: (type: Int) -> Unit) : BottomShee super.onStart() val dialog = dialog if (dialog != null) { - dialog.setCanceledOnTouchOutside(true) + dialog.setCanceledOnTouchOutside(false) val window = dialog.window if (window != null) { window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) diff --git a/app/src/main/java/com/audio/record/screen/test/fragment/child/ImageFragment.kt b/app/src/main/java/com/audio/record/screen/test/fragment/child/ImageFragment.kt index 421140f..8d92280 100644 --- a/app/src/main/java/com/audio/record/screen/test/fragment/child/ImageFragment.kt +++ b/app/src/main/java/com/audio/record/screen/test/fragment/child/ImageFragment.kt @@ -8,12 +8,14 @@ import androidx.core.view.isVisible import androidx.recyclerview.widget.LinearLayoutManager import com.audio.record.screen.test.adapter.ImageGroupAdapter import com.audio.record.screen.test.base.BaseFragment +import com.audio.record.screen.test.data.ImageGroup import com.audio.record.screen.test.databinding.FragmentImageBinding import com.audio.record.screen.test.tool.Common import com.audio.record.screen.test.tool.VideoFileHelper class ImageFragment : BaseFragment() { + private lateinit var imageGroupAdapter:ImageGroupAdapter companion object { @JvmStatic @@ -30,6 +32,27 @@ class ImageFragment : BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + imageGroupAdapter = ImageGroupAdapter(requireContext()) { + } + + binding.videoRecycler.run { + adapter = imageGroupAdapter + layoutManager = LinearLayoutManager(requireContext()) + } + + + } + + override fun onResume() { + super.onResume() + getInfo()?.let { + imageGroupAdapter.updateData(it) + } + + } + + private fun getInfo():List?{ val queryVideoInfoListInFolder = VideoFileHelper.queryGroupedImagesByDay(requireContext(),Common.imagesFolderDir) @@ -38,23 +61,13 @@ class ImageFragment : BaseFragment() { layoutEmpty.isVisible = true } Common.showLog("IMag isEmpty()") - return + return null } else { binding.run { layoutEmpty.isVisible = false } } - val imageGroupAdapter = ImageGroupAdapter(requireContext()) { - } - - binding.videoRecycler.run { - adapter = imageGroupAdapter.apply { - updateData(queryVideoInfoListInFolder) - } - layoutManager = LinearLayoutManager(requireContext()) - } - - + return queryVideoInfoListInFolder } diff --git a/app/src/main/java/com/audio/record/screen/test/fragment/child/VideoFragment.kt b/app/src/main/java/com/audio/record/screen/test/fragment/child/VideoFragment.kt index 4337444..513fcf6 100644 --- a/app/src/main/java/com/audio/record/screen/test/fragment/child/VideoFragment.kt +++ b/app/src/main/java/com/audio/record/screen/test/fragment/child/VideoFragment.kt @@ -17,6 +17,7 @@ import com.audio.record.screen.test.tool.Common import com.audio.record.screen.test.tool.VideoFileHelper class VideoFragment : BaseFragment() { + private lateinit var videoGroupAdapter:VideoGroupAdapter companion object { @JvmStatic @@ -33,7 +34,24 @@ class VideoFragment : BaseFragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + videoGroupAdapter = VideoGroupAdapter(requireContext()) { + } + binding.videoRecycler.run { + adapter = videoGroupAdapter + layoutManager = LinearLayoutManager(requireContext()) + } + } + override fun onResume() { + super.onResume() + getInfo()?.let { + videoGroupAdapter.updateData(it) + } + + } + + + private fun getInfo():MutableList?{ val queryVideoInfoListInFolder = VideoFileHelper.queryVideoInfoListInFolder(requireContext(),Common.videosFolderDir) @@ -43,7 +61,7 @@ class VideoFragment : BaseFragment() { layoutRecent.isVisible = false } Common.showLog("queryVideoInfoListInFolder.isEmpty()") - return + return null } else { binding.run { layoutEmpty.isVisible = false @@ -62,21 +80,9 @@ class VideoFragment : BaseFragment() { val removeRecent = removeRecent(listOf) if (removeRecent.isEmpty()||removeRecent[0].videos.isEmpty()) { Common.showLog("removeRecent.isEmpty()") - return + return null } - - - val videoGroupAdapter = VideoGroupAdapter(requireContext()) { - } - - binding.videoRecycler.run { - adapter = videoGroupAdapter.apply { - updateData(removeRecent) - } - layoutManager = LinearLayoutManager(requireContext()) - } - - + return removeRecent } diff --git a/app/src/main/java/com/audio/record/screen/test/service/FloatingCallback.kt b/app/src/main/java/com/audio/record/screen/test/service/FloatingCallback.kt index 634414e..c9f606b 100644 --- a/app/src/main/java/com/audio/record/screen/test/service/FloatingCallback.kt +++ b/app/src/main/java/com/audio/record/screen/test/service/FloatingCallback.kt @@ -1,5 +1,6 @@ package com.audio.record.screen.test.service +import android.graphics.Bitmap import androidx.camera.core.processing.SurfaceProcessorNode.In interface FloatingCallback { @@ -17,6 +18,6 @@ interface FloatingCallback { fun onRefreshRecordingStatus(status:Int){} - + fun onRefreshBitmap(bitmap:Bitmap){} } diff --git a/app/src/main/java/com/audio/record/screen/test/service/FloatingWindowBridge.kt b/app/src/main/java/com/audio/record/screen/test/service/FloatingWindowBridge.kt index de2f6a3..bc6d193 100644 --- a/app/src/main/java/com/audio/record/screen/test/service/FloatingWindowBridge.kt +++ b/app/src/main/java/com/audio/record/screen/test/service/FloatingWindowBridge.kt @@ -130,8 +130,8 @@ object FloatingWindowBridge { if (isBound) { Common.showLog("Service-=======unbindService 1111") context.unbindService(connection) - service = null - mBinder = null +// service = null +// mBinder = null isBound = false } } diff --git a/app/src/main/java/com/audio/record/screen/test/service/RecordState.kt b/app/src/main/java/com/audio/record/screen/test/service/RecordState.kt deleted file mode 100644 index b61f47b..0000000 --- a/app/src/main/java/com/audio/record/screen/test/service/RecordState.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.audio.record.screen.test.service - - -enum class RecordState { - DEFAULT, - RECORDING, - PAUSE } \ No newline at end of file diff --git a/app/src/main/java/com/audio/record/screen/test/service/ScreenRecordService.kt b/app/src/main/java/com/audio/record/screen/test/service/ScreenRecordService.kt index 2ffe7b4..16d2af2 100644 --- a/app/src/main/java/com/audio/record/screen/test/service/ScreenRecordService.kt +++ b/app/src/main/java/com/audio/record/screen/test/service/ScreenRecordService.kt @@ -40,8 +40,10 @@ import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat import androidx.core.view.isVisible import com.audio.record.screen.test.R +import com.audio.record.screen.test.activity.MainActivity1 import com.audio.record.screen.test.activity.PlayActivity import com.audio.record.screen.test.activity.ScreenPermissionActivity +import com.audio.record.screen.test.activity.ScreenshotAnimActivity import com.audio.record.screen.test.tool.Common import com.audio.record.screen.test.tool.ConstValue import com.audio.record.screen.test.tool.DraggableViewHelper @@ -78,7 +80,7 @@ class ScreenRecordService : Service() { private var imRecord: ImageView? = null private var tvRecordTime: TextView? = null private var imNoAudioRecord: ImageView? = null - private var imScreenshot:ImageView? = null + private var imScreenshot: ImageView? = null //截屏View private var screenshotView: View? = null @@ -161,10 +163,7 @@ class ScreenRecordService : Service() { inner class FloatingBinder : Binder() { fun getService() = this@ScreenRecordService - fun setCallback(cb: FloatingCallback) { - callbackRef = cb - } fun registerCallback(callback: FloatingCallback) { // 避免重复添加 @@ -215,13 +214,14 @@ class ScreenRecordService : Service() { } ConstValue.type_record_audio -> { + Common.showLog("Service--- 录制带音频的视频") isWithAudio = true val arrayOf = arrayOf("3", "2", "1") showCountDownView(arrayOf) } ConstValue.type_screenshot -> { - startScreenshot() + startScreenshot(isScreenshotViewAdded) } } ballType = null @@ -262,11 +262,12 @@ class ScreenRecordService : Service() { } return NotificationCompat.Builder(this, channelId) - .setContentTitle("屏幕录制中") - .setContentText("正在录制屏幕...") + .setContentTitle("") + .setContentText("") + .setPriority(NotificationCompat.PRIORITY_HIGH) .setCustomContentView(remoteViews) .setCustomBigContentView(remoteViews) - .setSmallIcon(R.drawable.test) + .setSmallIcon(R.mipmap.logo) .build() } @@ -274,18 +275,26 @@ class ScreenRecordService : Service() { /** * 开始截屏 */ - private fun startScreenshot(){ + private fun startScreenshot(showView: Boolean) { // TODO: 开始截屏 - mIntent?.let { intent-> - mediaProjectionManager.getMediaProjection(mCode, intent)?.let { mediaProjection-> + mIntent?.let { intent -> + mediaProjectionManager.getMediaProjection(mCode, intent)?.let { mediaProjection -> hideScreenshot() - ScreenCaptureHelper.startScreenCapture(this, mediaProjection) { + val intent = Intent(this, ScreenshotAnimActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + startActivity(intent) + ScreenCaptureHelper.startScreenCapture(this, mediaProjection) { bit -> + callbacks.forEach { + it.get()?.onRefreshBitmap(bit) + } //截屏完成 - showScreenshot() + if (showView) + showScreenshot() } } } } + @SuppressLint("ClickableViewAccessibility") fun showCameraView() { if (frontCameraView == null) { @@ -375,7 +384,7 @@ class ScreenRecordService : Service() { } Common.showLog("-------layoutParamsBall.x=${layoutParamsBall.x} layoutParamsBall.y=${layoutParamsBall.y}") } - if (!isBallViewAdded) { + if (!isBallViewAdded&&!isBallExpandViewAdded) { windowManager.addView(ballView, layoutParamsBall) isBallViewAdded = true } @@ -391,6 +400,17 @@ class ScreenRecordService : Service() { tvRecordTime = ballViewExpand!!.findViewById(R.id.tv_record_time) imNoAudioRecord = ballViewExpand!!.findViewById(R.id.ic_without_audio) imScreenshot = ballViewExpand!!.findViewById(R.id.ic_screenshot) + ballViewExpand!!.findViewById(R.id.ic_home).setOnClickListener { + + + val launchIntent = packageManager.getLaunchIntentForPackage(packageName) + launchIntent?.apply { + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + startActivity(this) + } + + + } imRecord?.setOnClickListener { it.isSelected.let { select -> @@ -454,7 +474,7 @@ class ScreenRecordService : Service() { aX = aX.coerceIn(0, screenWidth - aWidthPx) aY = aY.coerceIn(0, screenHeight - aHeightPx) - if (aX >= screenWidth/2) { + if (aX >= screenWidth / 2) { layoutParamsBallExpand.x = aX - 10.dpToPx(this) } else { @@ -509,7 +529,7 @@ class ScreenRecordService : Service() { windowManager, true ) { - startScreenshot() + startScreenshot(true) } } if (!isScreenshotViewAdded) { @@ -633,12 +653,14 @@ class ScreenRecordService : Service() { } if (countdownView?.windowToken == null) { + Common.showLog("Service--- 录制带音频的视频 addView") windowManager.addView(countdownView, layoutParamsCountDown) val tvCountdown = countdownView!!.findViewById(R.id.tv_countdown) index = 0 countDownHandler = Handler(Looper.getMainLooper()) animateNext(countdownValues, tvCountdown) { //倒计时结束后,开启录制 + Common.showLog("Service--- 倒计时结束") hideCountDown() mIntent?.let { intent -> mediaProjectionManager.getMediaProjection(mCode, intent) @@ -898,17 +920,18 @@ class ScreenRecordService : Service() { } - fun getViewStatus(){ + fun getViewStatus() { callbacks.forEach { - it.get()?.onRefreshViewShow(isWebcamViewAdded,isScreenshotViewAdded,isBallViewAdded) + it.get()?.onRefreshViewShow(isWebcamViewAdded, isScreenshotViewAdded, isBallViewAdded||isBallExpandViewAdded) } } - fun getRecordingStatus(){ + fun getRecordingStatus() { callbacks.forEach { it.get()?.onRefreshRecordingStatus(mRecordingStatus) } } + fun stopRecording() { // TODO: 录屏完成 mRecordingStatus = ConstValue.status_complete diff --git a/app/src/main/java/com/audio/record/screen/test/service/ScreenshotAnimExecutor.kt b/app/src/main/java/com/audio/record/screen/test/service/ScreenshotAnimExecutor.kt new file mode 100644 index 0000000..36d4602 --- /dev/null +++ b/app/src/main/java/com/audio/record/screen/test/service/ScreenshotAnimExecutor.kt @@ -0,0 +1,21 @@ +package com.audio.record.screen.test.service + +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import com.audio.record.screen.test.activity.ScreenPermissionActivity +import com.audio.record.screen.test.activity.ScreenshotAnimActivity +import com.audio.record.screen.test.tool.Common + +object ScreenshotAnimExecutor { + var latestBitmap: Bitmap? = null + + + fun show(context: Context, bitmap: Bitmap) { + latestBitmap = bitmap + Common.showLog("-----show-------------") + val intent = Intent(context, ScreenshotAnimActivity::class.java) + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + context.startActivity(intent) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/audio/record/screen/test/tool/ScreenCaptureHelper.kt b/app/src/main/java/com/audio/record/screen/test/tool/ScreenCaptureHelper.kt index 1ccf91d..9ab7626 100644 --- a/app/src/main/java/com/audio/record/screen/test/tool/ScreenCaptureHelper.kt +++ b/app/src/main/java/com/audio/record/screen/test/tool/ScreenCaptureHelper.kt @@ -1,5 +1,8 @@ package com.audio.record.screen.test.tool +import android.animation.Animator +import android.animation.AnimatorSet +import android.animation.ObjectAnimator import android.content.ContentValues import android.content.Context import android.content.Intent @@ -23,6 +26,7 @@ import android.view.WindowManager import android.view.animation.DecelerateInterpolator import android.widget.ImageView import com.audio.record.screen.test.R +import com.audio.record.screen.test.service.ScreenshotAnimExecutor import java.io.File import java.io.FileOutputStream @@ -37,7 +41,7 @@ object ScreenCaptureHelper { context: Context, mediaProjection: MediaProjection, folderName: String = Common.imagesFolderDir, - isOK:()->Unit + isOK:(bitmap:Bitmap)->Unit ) { val metrics = Resources.getSystem().displayMetrics val full = Common.getFullScreenSize(context) @@ -45,11 +49,11 @@ object ScreenCaptureHelper { val height = full.second val density = metrics.densityDpi - Common.showLog("startScreenCapture width=${width}, height=${height} density=${density} Thread=${Thread.currentThread().name}") +// Common.showLog("startScreenCapture width=${width}, height=${height} density=${density} Thread=${Thread.currentThread().name}") val imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 2) mediaProjection.registerCallback(object : MediaProjection.Callback() { override fun onStop() { - Common.showLog("startScreenCapture MediaProjection 被系统或用户停止") +// Common.showLog("startScreenCapture MediaProjection 被系统或用户停止") // 这里应该释放 MediaRecorder 和 VirtualDisplay 等 virtualDisplay?.release() mediaProjection.stop() @@ -67,9 +71,9 @@ object ScreenCaptureHelper { val image = imageReader.acquireLatestImage() if (image != null) { val bitmap = imageToBitmap(image) + isOK.invoke(bitmap) saveBitmap(context, bitmap, folderName) - showScreenshotPreviewAnimation(context, bitmap,width,height) - isOK.invoke() + image.close() } imageReader.close() @@ -165,14 +169,7 @@ object ScreenCaptureHelper { ).apply { gravity = Gravity.TOP or Gravity.START } - imageView.post { - Common.showLog("实际宽高 width=${imageView.width}, height=${imageView.height}") - - } - Common.showLog("layoutParams layoutParams x=${layoutParams.x}, y=${layoutParams.y}") windowManager.addView(inflate, layoutParams) - - val scale = 0.3f val targetWidth = (screenWidth * scale).toInt() val targetHeight = (screenHeight * scale).toInt() @@ -180,19 +177,28 @@ object ScreenCaptureHelper { val targetX = screenWidth - targetWidth - 20 val navigationBarHeight = Common.getNavigationBarHeight(context) val statusBarHeight = Common.getStatusBarHeight(context) - Common.showLog("navigationBarHeight=${navigationBarHeight}, statusBarHeight=${statusBarHeight} ") +// Common.showLog("navigationBarHeight=${navigationBarHeight}, statusBarHeight=${statusBarHeight} ") val targetY = screenHeight - targetHeight - navigationBarHeight - statusBarHeight - 20 - Common.showLog("宽高 targetWidth=${targetWidth}, targetHeight=${targetHeight} targetX = ${targetX} targetY = ${targetY}") +// Common.showLog("宽高 targetWidth=${targetWidth}, targetHeight=${targetHeight} targetX = ${targetX} targetY = ${targetY}") - inflate.animate() - .scaleX(scale) - .scaleY(scale) - .setDuration(600) - .setInterpolator(DecelerateInterpolator()) - .withEndAction { + + val scaleX = ObjectAnimator.ofFloat(inflate, "scaleX", 1f, scale) + val scaleY = ObjectAnimator.ofFloat(inflate, "scaleY", 1f, scale) + val animatorSet = AnimatorSet() + animatorSet.playTogether(scaleX, scaleY) + animatorSet.duration = 50 + animatorSet.interpolator = DecelerateInterpolator() + animatorSet.addListener(object : Animator.AnimatorListener { + override fun onAnimationStart(animation: Animator) { + Common.showLog("-----动画开始") + } + + override fun onAnimationEnd(animation: Animator) { + // 更新 layoutParams 和结束逻辑... + Common.showLog("-----动画结束") // 清除动画偏移 inflate.scaleX = 1f inflate.scaleY = 1f @@ -217,8 +223,11 @@ object ScreenCaptureHelper { } }, 3000) } - .start() + override fun onAnimationCancel(animation: Animator) {} + override fun onAnimationRepeat(animation: Animator) {} + }) + animatorSet.start() inflate.setOnClickListener { Common.showLog("-----点击小截图") } @@ -226,4 +235,87 @@ object ScreenCaptureHelper { } + + fun showScreenshotPreviewAnimationNew(context: Context, screenshotBitmap: Bitmap, screenWidth: Int, screenHeight: Int) { + val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager + val inflate = LayoutInflater.from(context).inflate(R.layout.floating_screenshot_anim, null) + val imageView = inflate.findViewById(R.id.image) + imageView.setImageBitmap(screenshotBitmap) + + // 初始全屏展示 + val layoutParams = WindowManager.LayoutParams( + screenWidth, + screenHeight, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY + else + WindowManager.LayoutParams.TYPE_PHONE, + WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or + WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL or + WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS, + PixelFormat.TRANSLUCENT + ).apply { + gravity = Gravity.TOP or Gravity.START + x = 0 + y = 0 + } + + windowManager.addView(inflate, layoutParams) + + // 动画目标位置与缩放比例 + val scale = 0.25f + val targetWidth = (screenWidth * scale).toInt() + val targetHeight = (screenHeight * scale).toInt() + val targetX = screenWidth - targetWidth - 32 // 留点边距 + val targetY = screenHeight - targetHeight - Common.getNavigationBarHeight(context) - 32 + + // 设置原始位置(居中) + inflate.pivotX = 0f + inflate.pivotY = 0f + inflate.translationX = 0f + inflate.translationY = 0f + inflate.scaleX = 1f + inflate.scaleY = 1f + + // 执行缩放+位移动画 + inflate.animate() + .scaleX(scale) + .scaleY(scale) + .translationX(targetX.toFloat()) + .translationY(targetY.toFloat()) + .setDuration(500) + .setInterpolator(DecelerateInterpolator()) + .withStartAction { + Common.showLog("📸 截图动画开始") + } + .withEndAction { + Common.showLog("✅ 截图动画结束:变成小图") + // 动画后清除 scale/translation 状态并更新窗口布局为小图位置 + inflate.scaleX = 1f + inflate.scaleY = 1f + inflate.translationX = 0f + inflate.translationY = 0f + + layoutParams.width = targetWidth + layoutParams.height = targetHeight + layoutParams.x = targetX + layoutParams.y = targetY + windowManager.updateViewLayout(inflate, layoutParams) + + // 延时关闭 + inflate.postDelayed({ + try { + windowManager.removeView(inflate) + } catch (e: Exception) { + e.printStackTrace() + } + }, 3000) + } + .start() + + inflate.setOnClickListener { + Common.showLog("🖼️ 点击了截图缩略图") + } + } + } diff --git a/app/src/main/res/drawable/bg_welcome.png b/app/src/main/res/drawable/bg_welcome.png new file mode 100644 index 0000000..8aa0609 Binary files /dev/null and b/app/src/main/res/drawable/bg_welcome.png differ diff --git a/app/src/main/res/drawable/bg_welcome_icon.png b/app/src/main/res/drawable/bg_welcome_icon.png new file mode 100644 index 0000000..0faa931 Binary files /dev/null and b/app/src/main/res/drawable/bg_welcome_icon.png differ diff --git a/app/src/main/res/layout/activity_welcome.xml b/app/src/main/res/layout/activity_welcome.xml new file mode 100644 index 0000000..888bd8c --- /dev/null +++ b/app/src/main/res/layout/activity_welcome.xml @@ -0,0 +1,28 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/adapter_video_date.xml b/app/src/main/res/layout/adapter_video_date.xml index c99e836..1479862 100644 --- a/app/src/main/res/layout/adapter_video_date.xml +++ b/app/src/main/res/layout/adapter_video_date.xml @@ -2,7 +2,7 @@ + android:layout_height="wrap_content"> @@ -61,6 +61,7 @@ android:layout_height="wrap_content" android:layout_marginTop="6dp" android:text="@string/app_name" + android:visibility="gone" android:textColor="@color/color_8D8D8D" android:textSize="11sp" /> @@ -69,9 +70,15 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/app_name" + android:layout_marginTop="6dp" android:textColor="@color/color_8D8D8D" android:textSize="11sp" /> + \ No newline at end of file diff --git a/app/src/main/res/layout/custom_notification.xml b/app/src/main/res/layout/custom_notification.xml index 2dccf2b..1fb8d40 100644 --- a/app/src/main/res/layout/custom_notification.xml +++ b/app/src/main/res/layout/custom_notification.xml @@ -10,98 +10,105 @@ - + + + + + + - + + + + - - + + + + + - + + + + + + - + + + + - - + + + + + - + + + + + + - + + + + - - - + + + + + + + + + + + - + + + + - - - + + + + + + + + + + + - + + + + - - + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/floating_screenshot_anim.xml b/app/src/main/res/layout/floating_screenshot_anim.xml index cdcb6f7..e56fba5 100644 --- a/app/src/main/res/layout/floating_screenshot_anim.xml +++ b/app/src/main/res/layout/floating_screenshot_anim.xml @@ -1,12 +1,21 @@ + android:layout_width="match_parent" + android:layout_height="match_parent"> + + + android:layout_gravity="center" + android:text="@string/Screenshot_please_wait" + android:textColor="@color/black" + android:textSize="21sp" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml index adc933b..a6ba405 100644 --- a/app/src/main/res/layout/fragment_main.xml +++ b/app/src/main/res/layout/fragment_main.xml @@ -10,7 +10,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="31dp" - android:text="@string/Collection" + android:text="@string/app_name" android:textColor="@color/black" android:textSize="39sp" app:layout_constraintLeft_toLeftOf="parent" diff --git a/app/src/main/res/layout/fragment_record_normal.xml b/app/src/main/res/layout/fragment_record_normal.xml index fe1a610..a7169bc 100644 --- a/app/src/main/res/layout/fragment_record_normal.xml +++ b/app/src/main/res/layout/fragment_record_normal.xml @@ -11,7 +11,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="31dp" - android:text="@string/Collection" + android:text="@string/app_name" android:textColor="@color/black" android:textSize="39sp" app:layout_constraintLeft_toLeftOf="parent" diff --git a/app/src/main/res/layout/fragment_recording.xml b/app/src/main/res/layout/fragment_recording.xml index c547b65..0c06faa 100644 --- a/app/src/main/res/layout/fragment_recording.xml +++ b/app/src/main/res/layout/fragment_recording.xml @@ -15,6 +15,7 @@ android:text="@string/app_name" android:textColor="@color/title_color" android:textSize="28sp" + android:visibility="gone" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout/fragment_video.xml b/app/src/main/res/layout/fragment_video.xml index 4cee54a..f08938b 100644 --- a/app/src/main/res/layout/fragment_video.xml +++ b/app/src/main/res/layout/fragment_video.xml @@ -76,7 +76,7 @@ diff --git a/app/src/main/res/mipmap-xxxhdpi/logo.png b/app/src/main/res/mipmap-xxxhdpi/logo.png new file mode 100644 index 0000000..9364e6c Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/logo.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/test.jpg b/app/src/main/res/mipmap-xxxhdpi/test.jpg deleted file mode 100644 index 9429440..0000000 Binary files a/app/src/main/res/mipmap-xxxhdpi/test.jpg and /dev/null differ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c311892..9f80fd6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,6 +19,8 @@ through the notification panel There\'s nothing here. Recent New + Running... + Screenshot, please wait... -100 100