LAFBackgroundImageActivity.kt raw

   1  package io.github.domi04151309.alwayson.activities
   2  
   3  import android.Manifest
   4  import android.content.Intent
   5  import android.content.pm.PackageManager
   6  import android.graphics.Bitmap
   7  import android.graphics.BitmapFactory
   8  import android.os.Build
   9  import android.os.Bundle
  10  import android.provider.MediaStore
  11  import android.util.Base64
  12  import android.widget.ImageView
  13  import android.widget.Toast
  14  import androidx.activity.result.ActivityResult
  15  import androidx.activity.result.ActivityResultCallback
  16  import androidx.activity.result.ActivityResultLauncher
  17  import androidx.activity.result.contract.ActivityResultContracts
  18  import androidx.core.app.ActivityCompat
  19  import androidx.core.content.edit
  20  import androidx.core.graphics.scale
  21  import androidx.recyclerview.widget.LinearLayoutManager
  22  import androidx.recyclerview.widget.RecyclerView
  23  import io.github.domi04151309.alwayson.R
  24  import io.github.domi04151309.alwayson.actions.alwayson.AlwaysOn
  25  import io.github.domi04151309.alwayson.adapters.LayoutListAdapter
  26  import io.github.domi04151309.alwayson.helpers.P
  27  import java.io.ByteArrayOutputStream
  28  import java.io.InputStream
  29  import java.lang.Integer.min
  30  
  31  class LAFBackgroundImageActivity :
  32      BaseActivity(),
  33      ActivityResultCallback<ActivityResult>,
  34      LayoutListAdapter.OnItemClickListener {
  35      internal var value: String = P.BACKGROUND_IMAGE_DEFAULT
  36      private lateinit var preview: ImageView
  37      private lateinit var layoutList: RecyclerView
  38      private lateinit var customImageResult: ActivityResultLauncher<Intent>
  39  
  40      private val drawables =
  41          arrayOf(
  42              R.drawable.ic_close,
  43              R.drawable.unsplash_daniel_olah_1,
  44              R.drawable.unsplash_daniel_olah_2,
  45              R.drawable.unsplash_daniel_olah_3,
  46              R.drawable.unsplash_daniel_olah_4,
  47              R.drawable.unsplash_daniel_olah_5,
  48              R.drawable.unsplash_daniel_olah_6,
  49              R.drawable.unsplash_daniel_olah_7,
  50              R.drawable.unsplash_daniel_olah_8,
  51              R.drawable.unsplash_filip_baotic_1,
  52              R.drawable.unsplash_tyler_lastovich_1,
  53              R.drawable.unsplash_tyler_lastovich_2,
  54              R.drawable.unsplash_tyler_lastovich_3,
  55              R.drawable.ic_color_draw_over_other_apps,
  56          )
  57  
  58      @Suppress("CyclomaticComplexMethod")
  59      private fun positionToString(position: Int): String =
  60          when (position) {
  61              ITEM_NONE -> P.BACKGROUND_IMAGE_NONE
  62              ITEM_DANIEL_OLAH_1 -> P.BACKGROUND_IMAGE_DANIEL_OLAH_1
  63              ITEM_DANIEL_OLAH_2 -> P.BACKGROUND_IMAGE_DANIEL_OLAH_2
  64              ITEM_DANIEL_OLAH_3 -> P.BACKGROUND_IMAGE_DANIEL_OLAH_3
  65              ITEM_DANIEL_OLAH_4 -> P.BACKGROUND_IMAGE_DANIEL_OLAH_4
  66              ITEM_DANIEL_OLAH_5 -> P.BACKGROUND_IMAGE_DANIEL_OLAH_5
  67              ITEM_DANIEL_OLAH_6 -> P.BACKGROUND_IMAGE_DANIEL_OLAH_6
  68              ITEM_DANIEL_OLAH_7 -> P.BACKGROUND_IMAGE_DANIEL_OLAH_7
  69              ITEM_DANIEL_OLAH_8 -> P.BACKGROUND_IMAGE_DANIEL_OLAH_8
  70              ITEM_FILIP_BAOTIC_1 -> P.BACKGROUND_IMAGE_FILIP_BAOTIC_1
  71              ITEM_TYLER_LASTOVICH_1 -> P.BACKGROUND_IMAGE_TYLER_LASTOVICH_1
  72              ITEM_TYLER_LASTOVICH_2 -> P.BACKGROUND_IMAGE_TYLER_LASTOVICH_2
  73              ITEM_TYLER_LASTOVICH_3 -> P.BACKGROUND_IMAGE_TYLER_LASTOVICH_3
  74              ITEM_CUSTOM -> P.BACKGROUND_IMAGE_CUSTOM
  75              else -> P.BACKGROUND_IMAGE_DEFAULT
  76          }
  77  
  78      @Suppress("CyclomaticComplexMethod")
  79      private fun stringToPosition(string: String): Int =
  80          when (string) {
  81              P.BACKGROUND_IMAGE_NONE -> ITEM_NONE
  82              P.BACKGROUND_IMAGE_DANIEL_OLAH_1 -> ITEM_DANIEL_OLAH_1
  83              P.BACKGROUND_IMAGE_DANIEL_OLAH_2 -> ITEM_DANIEL_OLAH_2
  84              P.BACKGROUND_IMAGE_DANIEL_OLAH_3 -> ITEM_DANIEL_OLAH_3
  85              P.BACKGROUND_IMAGE_DANIEL_OLAH_4 -> ITEM_DANIEL_OLAH_4
  86              P.BACKGROUND_IMAGE_DANIEL_OLAH_5 -> ITEM_DANIEL_OLAH_5
  87              P.BACKGROUND_IMAGE_DANIEL_OLAH_6 -> ITEM_DANIEL_OLAH_6
  88              P.BACKGROUND_IMAGE_DANIEL_OLAH_7 -> ITEM_DANIEL_OLAH_7
  89              P.BACKGROUND_IMAGE_DANIEL_OLAH_8 -> ITEM_DANIEL_OLAH_8
  90              P.BACKGROUND_IMAGE_FILIP_BAOTIC_1 -> ITEM_FILIP_BAOTIC_1
  91              P.BACKGROUND_IMAGE_TYLER_LASTOVICH_1 -> ITEM_TYLER_LASTOVICH_1
  92              P.BACKGROUND_IMAGE_TYLER_LASTOVICH_2 -> ITEM_TYLER_LASTOVICH_2
  93              P.BACKGROUND_IMAGE_TYLER_LASTOVICH_3 -> ITEM_TYLER_LASTOVICH_3
  94              P.BACKGROUND_IMAGE_CUSTOM -> ITEM_CUSTOM
  95              else -> ITEM_NONE
  96          }
  97  
  98      override fun onCreate(savedInstanceState: Bundle?) {
  99          super.onCreate(savedInstanceState)
 100          setContentView(R.layout.activity_layout_list)
 101  
 102          preview = findViewById(R.id.preview)
 103          layoutList = findViewById(R.id.layout_list)
 104  
 105          customImageResult =
 106              registerForActivityResult(ActivityResultContracts.StartActivityForResult(), this)
 107  
 108          layoutList.layoutManager =
 109              LinearLayoutManager(this).apply {
 110                  orientation = LinearLayoutManager.HORIZONTAL
 111              }
 112          layoutList.adapter =
 113              LayoutListAdapter(
 114                  drawables,
 115                  resources.getStringArray(R.array.pref_ao_background_image_array_display),
 116                  this,
 117              )
 118      }
 119  
 120      override fun onActivityResult(result: ActivityResult) {
 121          if (result.resultCode == RESULT_OK) {
 122              if (result.data == null) return
 123              @Suppress("LabeledExpression")
 124              Thread {
 125                  val inputStream: InputStream? =
 126                      contentResolver.openInputStream(
 127                          result.data?.data
 128                              ?: return@Thread,
 129                      )
 130  
 131                  var bitmap = BitmapFactory.decodeStream(inputStream) ?: return@Thread
 132                  val size = min(bitmap.width, bitmap.height)
 133                  bitmap =
 134                      Bitmap.createBitmap(
 135                          bitmap,
 136                          (bitmap.width - size) / 2,
 137                          (bitmap.height - size) / 2,
 138                          size,
 139                          size,
 140                      )
 141                  if (bitmap.width > MAXIMUM_BACKGROUND_RESOLUTION) {
 142                      bitmap =
 143                          bitmap.scale(MAXIMUM_BACKGROUND_RESOLUTION, MAXIMUM_BACKGROUND_RESOLUTION)
 144                  }
 145  
 146                  val os = ByteArrayOutputStream()
 147                  bitmap.compress(Bitmap.CompressFormat.JPEG, BACKGROUND_QUALITY, os)
 148                  val encoded: String =
 149                      Base64.encodeToString(
 150                          os.toByteArray(),
 151                          Base64.DEFAULT,
 152                      )
 153                  runOnUiThread { preview.setImageBitmap(bitmap) }
 154                  P.getPreferences(this).edit {
 155                      putString(P.CUSTOM_BACKGROUND, encoded)
 156                  }
 157              }.start()
 158          }
 159      }
 160  
 161      override fun onItemClick(position: Int) {
 162          if (position == ITEM_CUSTOM) {
 163              showCustomImage()
 164              if (hasPermission()) {
 165                  customImageResult.launch(
 166                      Intent(Intent.ACTION_PICK).apply {
 167                          setDataAndType(
 168                              MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
 169                              "image/*",
 170                          )
 171                      },
 172                  )
 173              } else {
 174                  Toast.makeText(
 175                      this@LAFBackgroundImageActivity,
 176                      R.string.missing_permissions,
 177                      Toast.LENGTH_LONG,
 178                  ).show()
 179                  ActivityCompat.requestPermissions(
 180                      this@LAFBackgroundImageActivity,
 181                      arrayOf(
 182                          if (
 183                              Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
 184                          ) {
 185                              Manifest.permission.READ_MEDIA_IMAGES
 186                          } else {
 187                              Manifest.permission.READ_EXTERNAL_STORAGE
 188                          },
 189                      ),
 190                      0,
 191                  )
 192              }
 193          } else {
 194              preview.setImageResource(drawables[position])
 195          }
 196          value = positionToString(position)
 197          AlwaysOn.finish()
 198      }
 199  
 200      override fun onStart() {
 201          super.onStart()
 202          value = P.getPreferences(this).getString(P.BACKGROUND_IMAGE, P.BACKGROUND_IMAGE_DEFAULT)
 203              ?: P.BACKGROUND_IMAGE_DEFAULT
 204          setSelectedItem(layoutList.adapter as LayoutListAdapter, stringToPosition(value))
 205      }
 206  
 207      override fun onStop() {
 208          super.onStop()
 209          P.getPreferences(this).edit { putString(P.BACKGROUND_IMAGE, value) }
 210      }
 211  
 212      private fun showCustomImage() {
 213          val decoded = Base64.decode(P.getPreferences(this).getString(P.CUSTOM_BACKGROUND, ""), 0)
 214          preview.setImageBitmap(BitmapFactory.decodeByteArray(decoded, 0, decoded.size))
 215      }
 216  
 217      private fun setSelectedItem(
 218          adapter: LayoutListAdapter,
 219          position: Int,
 220      ) {
 221          if (position == ITEM_CUSTOM) {
 222              showCustomImage()
 223          } else {
 224              preview.setImageResource(drawables[position])
 225          }
 226          adapter.setSelectedItem(position)
 227      }
 228  
 229      private fun hasPermission(): Boolean =
 230          applicationContext.checkSelfPermission(
 231              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
 232                  Manifest.permission.READ_MEDIA_IMAGES
 233              } else {
 234                  Manifest.permission.READ_EXTERNAL_STORAGE
 235              },
 236          ) == PackageManager.PERMISSION_GRANTED
 237  
 238      companion object {
 239          private const val ITEM_NONE = 0
 240          private const val ITEM_DANIEL_OLAH_1 = 1
 241          private const val ITEM_DANIEL_OLAH_2 = 2
 242          private const val ITEM_DANIEL_OLAH_3 = 3
 243          private const val ITEM_DANIEL_OLAH_4 = 4
 244          private const val ITEM_DANIEL_OLAH_5 = 5
 245          private const val ITEM_DANIEL_OLAH_6 = 6
 246          private const val ITEM_DANIEL_OLAH_7 = 7
 247          private const val ITEM_DANIEL_OLAH_8 = 8
 248          private const val ITEM_FILIP_BAOTIC_1 = 9
 249          private const val ITEM_TYLER_LASTOVICH_1 = 10
 250          private const val ITEM_TYLER_LASTOVICH_2 = 11
 251          private const val ITEM_TYLER_LASTOVICH_3 = 12
 252          private const val ITEM_CUSTOM = 13
 253          private const val MAXIMUM_BACKGROUND_RESOLUTION = 1080
 254          private const val BACKGROUND_QUALITY = 60
 255      }
 256  }
 257