From a6dbd976fd3597d05cbddf0c62c71afa1e396ac6 Mon Sep 17 00:00:00 2001 From: Agnieszka C <85929121+Aga-C@users.noreply.github.com> Date: Sat, 28 Aug 2021 10:53:42 +0200 Subject: [PATCH] Added widget for quick recording starting (#22) --- app/src/main/AndroidManifest.xml | 21 ++++ .../voicerecorder/activities/MainActivity.kt | 14 +++ .../WidgetRecordDisplayConfigureActivity.kt | 101 ++++++++++++++++++ .../voicerecorder/extensions/Context.kt | 12 +++ .../helpers/MyWidgetRecordDisplayProvider.kt | 51 +++++++++ .../voicerecorder/services/RecorderService.kt | 4 + .../drawable/ic_microphone_widget_icon.xml | 4 + .../main/res/layout/widget_record_display.xml | 6 ++ .../layout/widget_record_display_config.xml | 61 +++++++++++ app/src/main/res/values/dimens.xml | 1 + .../main/res/xml/widget_record_display.xml | 8 ++ 11 files changed, 283 insertions(+) create mode 100644 app/src/main/kotlin/com/simplemobiletools/voicerecorder/activities/WidgetRecordDisplayConfigureActivity.kt create mode 100644 app/src/main/kotlin/com/simplemobiletools/voicerecorder/helpers/MyWidgetRecordDisplayProvider.kt create mode 100644 app/src/main/res/drawable/ic_microphone_widget_icon.xml create mode 100644 app/src/main/res/layout/widget_record_display.xml create mode 100644 app/src/main/res/layout/widget_record_display_config.xml create mode 100644 app/src/main/res/xml/widget_record_display.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2ecb11b..8b3d422 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -28,6 +28,27 @@ android:roundIcon="@mipmap/ic_launcher" android:theme="@style/AppTheme"> + + + + + + + + + + + + + + diff --git a/app/src/main/kotlin/com/simplemobiletools/voicerecorder/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/activities/MainActivity.kt index 0d10d93..21458d1 100644 --- a/app/src/main/kotlin/com/simplemobiletools/voicerecorder/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/activities/MainActivity.kt @@ -18,6 +18,10 @@ import kotlinx.android.synthetic.main.activity_main.* class MainActivity : SimpleActivity() { + companion object { + const val RECORD_INTENT_ACTION = "RECORD_ACTION"; + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) @@ -40,6 +44,16 @@ class MainActivity : SimpleActivity() { super.onResume() getPagerAdapter()?.onResume() setupTabColors() + + if (intent.action == RECORD_INTENT_ACTION) { + view_pager.currentItem = 0 + Intent(this@MainActivity, RecorderService::class.java).apply { + try { + startService(this) + } catch (ignored: Exception) { + } + } + } } override fun onDestroy() { diff --git a/app/src/main/kotlin/com/simplemobiletools/voicerecorder/activities/WidgetRecordDisplayConfigureActivity.kt b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/activities/WidgetRecordDisplayConfigureActivity.kt new file mode 100644 index 0000000..9304cc2 --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/activities/WidgetRecordDisplayConfigureActivity.kt @@ -0,0 +1,101 @@ +package com.simplemobiletools.voicerecorder.activities + +import android.app.Activity +import android.appwidget.AppWidgetManager +import android.content.Intent +import android.graphics.Color +import android.os.Bundle +import android.widget.SeekBar +import com.simplemobiletools.commons.dialogs.ColorPickerDialog +import com.simplemobiletools.commons.extensions.adjustAlpha +import com.simplemobiletools.commons.extensions.applyColorFilter +import com.simplemobiletools.commons.extensions.setFillWithStroke +import com.simplemobiletools.commons.helpers.DEFAULT_WIDGET_BG_COLOR +import com.simplemobiletools.commons.helpers.IS_CUSTOMIZING_COLORS +import com.simplemobiletools.voicerecorder.R +import com.simplemobiletools.voicerecorder.extensions.config +import com.simplemobiletools.voicerecorder.helpers.MyWidgetRecordDisplayProvider +import kotlinx.android.synthetic.main.widget_record_display_config.* + +class WidgetRecordDisplayConfigureActivity : SimpleActivity() { + private var mWidgetAlpha = 0f + private var mWidgetId = 0 + private var mWidgetColor = 0 + private var mWidgetColorWithoutTransparency = 0 + + public override fun onCreate(savedInstanceState: Bundle?) { + useDynamicTheme = false + super.onCreate(savedInstanceState) + setResult(Activity.RESULT_CANCELED) + setContentView(R.layout.widget_record_display_config) + initVariables() + + val isCustomizingColors = intent.extras?.getBoolean(IS_CUSTOMIZING_COLORS) ?: false + mWidgetId = intent.extras?.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID) ?: AppWidgetManager.INVALID_APPWIDGET_ID + + if (mWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID && !isCustomizingColors) { + finish() + } + + config_save.setOnClickListener { saveConfig() } + config_widget_color.setOnClickListener { pickBackgroundColor() } + } + + private fun initVariables() { + mWidgetColor = config.widgetBgColor + mWidgetAlpha = if (mWidgetColor == DEFAULT_WIDGET_BG_COLOR) { + 1f + } else { + Color.alpha(mWidgetColor) / 255.toFloat() + } + + mWidgetColorWithoutTransparency = Color.rgb(Color.red(mWidgetColor), Color.green(mWidgetColor), Color.blue(mWidgetColor)) + config_widget_seekbar.setOnSeekBarChangeListener(seekbarChangeListener) + config_widget_seekbar.progress = (mWidgetAlpha * 100).toInt() + updateColors() + } + + private fun saveConfig() { + config.widgetBgColor = mWidgetColor + requestWidgetUpdate() + + Intent().apply { + putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mWidgetId) + setResult(Activity.RESULT_OK, this) + } + finish() + } + + private fun pickBackgroundColor() { + ColorPickerDialog(this, mWidgetColorWithoutTransparency) { wasPositivePressed, color -> + if (wasPositivePressed) { + mWidgetColorWithoutTransparency = color + updateColors() + } + } + } + + private fun requestWidgetUpdate() { + Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null, this, MyWidgetRecordDisplayProvider::class.java).apply { + putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, intArrayOf(mWidgetId)) + sendBroadcast(this) + } + } + + private fun updateColors() { + mWidgetColor = mWidgetColorWithoutTransparency.adjustAlpha(mWidgetAlpha) + config_widget_color.setFillWithStroke(mWidgetColor, Color.BLACK) + config_image.background.mutate().applyColorFilter(mWidgetColor) + } + + private val seekbarChangeListener = object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) { + mWidgetAlpha = progress.toFloat() / 100.toFloat() + updateColors() + } + + override fun onStartTrackingTouch(seekBar: SeekBar) {} + + override fun onStopTrackingTouch(seekBar: SeekBar) {} + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/voicerecorder/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/extensions/Context.kt index 3ea8dfd..a4a5f9d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/voicerecorder/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/extensions/Context.kt @@ -1,6 +1,18 @@ package com.simplemobiletools.voicerecorder.extensions import android.content.Context +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.drawable.Drawable import com.simplemobiletools.voicerecorder.helpers.Config val Context.config: Config get() = Config.newInstance(applicationContext) + +fun Context.drawableToBitmap(drawable: Drawable): Bitmap { + val size = (60 * resources.displayMetrics.density).toInt() + val mutableBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888) + val canvas = Canvas(mutableBitmap) + drawable.setBounds(0, 0, size, size) + drawable.draw(canvas) + return mutableBitmap +} diff --git a/app/src/main/kotlin/com/simplemobiletools/voicerecorder/helpers/MyWidgetRecordDisplayProvider.kt b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/helpers/MyWidgetRecordDisplayProvider.kt new file mode 100644 index 0000000..365865e --- /dev/null +++ b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/helpers/MyWidgetRecordDisplayProvider.kt @@ -0,0 +1,51 @@ +package com.simplemobiletools.voicerecorder.helpers + +import android.app.PendingIntent +import android.appwidget.AppWidgetManager +import android.appwidget.AppWidgetProvider +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import android.graphics.Color +import android.widget.RemoteViews +import com.simplemobiletools.commons.extensions.getColoredDrawableWithColor +import com.simplemobiletools.voicerecorder.R +import com.simplemobiletools.voicerecorder.extensions.config +import com.simplemobiletools.voicerecorder.activities.MainActivity +import com.simplemobiletools.voicerecorder.extensions.drawableToBitmap + +class MyWidgetRecordDisplayProvider : AppWidgetProvider() { + private val OPEN_APP_INTENT_ID = 1 + + override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { + appWidgetManager.getAppWidgetIds(getComponentName(context)).forEach { + RemoteViews(context.packageName, R.layout.widget_record_display).apply { + setupAppOpenIntent(context, this) + + val selectedColor = context.config.widgetBgColor + val alpha = Color.alpha(selectedColor) + + val bmp = getColoredIcon(context, selectedColor, alpha) + setImageViewBitmap(R.id.record_display_btn, bmp) + + appWidgetManager.updateAppWidget(it, this) + } + } + } + + private fun getComponentName(context: Context) = ComponentName(context, MyWidgetRecordDisplayProvider::class.java) + + private fun setupAppOpenIntent(context: Context, views: RemoteViews) { + Intent(context, MainActivity::class.java).apply { + action = MainActivity.RECORD_INTENT_ACTION; + val pendingIntent = PendingIntent.getActivity(context, OPEN_APP_INTENT_ID, this, PendingIntent.FLAG_CANCEL_CURRENT) + views.setOnClickPendingIntent(R.id.record_display_btn, pendingIntent) + } + } + + private fun getColoredIcon(context: Context, color: Int, alpha: Int): Bitmap { + val drawable = context.resources.getColoredDrawableWithColor(R.drawable.ic_microphone_vector, color, alpha) + return context.drawableToBitmap(drawable) + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/voicerecorder/services/RecorderService.kt b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/services/RecorderService.kt index 08f0ef4..b021286 100644 --- a/app/src/main/kotlin/com/simplemobiletools/voicerecorder/services/RecorderService.kt +++ b/app/src/main/kotlin/com/simplemobiletools/voicerecorder/services/RecorderService.kt @@ -60,6 +60,10 @@ class RecorderService : Service() { // mp4 output format with aac encoding should produce good enough m4a files according to https://stackoverflow.com/a/33054794/1967672 private fun startRecording() { + if (status == RECORDING_RUNNING) { + return + } + val baseFolder = if (isQPlus()) { cacheDir } else { diff --git a/app/src/main/res/drawable/ic_microphone_widget_icon.xml b/app/src/main/res/drawable/ic_microphone_widget_icon.xml new file mode 100644 index 0000000..095ea1d --- /dev/null +++ b/app/src/main/res/drawable/ic_microphone_widget_icon.xml @@ -0,0 +1,4 @@ + + + diff --git a/app/src/main/res/layout/widget_record_display.xml b/app/src/main/res/layout/widget_record_display.xml new file mode 100644 index 0000000..062284c --- /dev/null +++ b/app/src/main/res/layout/widget_record_display.xml @@ -0,0 +1,6 @@ + + diff --git a/app/src/main/res/layout/widget_record_display_config.xml b/app/src/main/res/layout/widget_record_display_config.xml new file mode 100644 index 0000000..edb7e2c --- /dev/null +++ b/app/src/main/res/layout/widget_record_display_config.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + +