API Androida niestety nie dostarcza nam w standardzie żadnego mechanizmu umożliwiającego wybór pliku z systemu plików. W takim przypadku nie pozostaje nam nic innego jak zaimplementować to samemu lub skorzystać z gotowej biblioteki.

Postanowiłem bazować na file chooser’ze zaimplementowanym przez Rogera Keaysa. Jest on dostępny pod poniższym adresem: https://rogerkeays.com/simple-android-file-chooser.

Moja implementacja wygląda w następujący sposób:

class FileChooser(val activity: Activity, val fileListener: FileSelectedListener, val maxFileSize: Double) {
  private lazy val messageMaker = wire(classOf[MessageMaker])
  private val parentDir = ".."
  private val mb = 1024.0 * 1024.0
  private val dialog = new Dialog(activity)
  private val list = new ListView(activity)
  private var currentPath: File = _

  list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    override def onItemClick(parent: AdapterView[_], view: View, position: Int, id: Long): Unit = {
      val fileChosen: String = list.getItemAtPosition(position).asInstanceOf[String]
      val chosenFile: File = getChosenFile(fileChosen)
      if (chosenFile.isDirectory) {
        refresh(chosenFile)
      }
      else {
        val sizeInMB: Double = chosenFile.length / mb
        if (sizeInMB > maxFileSize) {
          messageMaker.info("Selected file is too large")
        }
        else {
          if (fileListener != null) {
            fileListener.fileSelected(chosenFile)
          }
          dialog.dismiss()
        }
      }
    }
  })
  dialog.setContentView(list)
  dialog.getWindow.setLayout(MATCH_PARENT, MATCH_PARENT)
  refresh(Environment.getExternalStorageDirectory)

  def showDialog() {
    dialog.show()
  }

  /**
   * Sort, filter and display the files for the given path.
   */
  private def refresh(path: File) {
    this.currentPath = path
    if (path.exists) {
      val dirs: Array[File] = path.listFiles(new FileFilter() {
        def accept(file: File): Boolean = {
          file.isDirectory && file.canRead
        }
      })
      val files: Array[File] = path.listFiles(new FileFilter() {
        def accept(file: File): Boolean = {
          !file.isDirectory && file.canRead
        }
      })
      dirs.sortWith(_.getName > _.getName)
      files.sortWith(_.getName > _.getName)

      // convert to an array
      val i: Int = 0
      var fileList = ArrayBuffer[String]()

      if (path.getParentFile != null) {
        fileList += parentDir
      }
      dirs.foreach(d => fileList += d.getName)
      files.foreach(f => fileList += f.getName)

      // refresh the user interface
      dialog.setTitle(currentPath.getPath)
      list.setAdapter(new ArrayAdapter(activity, android.R.layout.simple_list_item_1, fileList.toArray) {
        override def getView(pos: Int, view: View, parent: ViewGroup): View = {
          val superView = super.getView(pos, view, parent)
          superView.asInstanceOf[TextView].setSingleLine(true)
          superView
        }
      })
    }
  }

  private def getChosenFile(fileChosen: String): File = {
    if (fileChosen == parentDir) {
      currentPath.getParentFile
    }
    else {
      new File(currentPath, fileChosen)
    }
  }
}
trait FileSelectedListener {
  def fileSelected(file: File)
}

Główną zmianą (oczywiście poza napisaniem tego w języku Scala) jest dodanie ograniczenia na maksymalną wielkość pliku. Po wyborze pliku, jeżeli jego rozmiar przekracza ustawiony maksymalny rozmiar to zostaje wyświetlony komunkat z informacją, a plik nie zostaje dodany.