Enable DMG file selection

This commit is contained in:
Davide Depau 2018-08-16 16:21:43 +02:00
parent baeed60324
commit 1063a3024d
8 changed files with 110 additions and 36 deletions

View File

@ -30,9 +30,13 @@ dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.android.support:design:28.0.0-rc01'
implementation 'com.android.support:recyclerview-v7:28.0.0-rc01'
implementation 'com.github.isabsent:filepicker:1.1.01'
// implementation 'com.github.mjdev:libaums:0.5.5'
implementation project(':libaums')
implementation project(':dmg2img')
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

View File

@ -1,11 +1,24 @@
package eu.depau.etchdroid.abc
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import com.github.isabsent.filepicker.SimpleFilePickerDialog
import eu.depau.etchdroid.StateKeeper
abstract class WizardActivity : AppCompatActivity() {
abstract class WizardActivity : AppCompatActivity(), SimpleFilePickerDialog.InteractionListenerString {
override fun onResult(dialogTag: String, which: Int, extras: Bundle): Boolean {
if (StateKeeper.currentFragment is SimpleFilePickerDialog.InteractionListenerString)
return (StateKeeper.currentFragment as SimpleFilePickerDialog.InteractionListenerString).onResult(dialogTag, which, extras)
throw RuntimeException("Wrong fragment type")
}
override fun showListItemDialog(title: String?, folderPath: String?, mode: SimpleFilePickerDialog.CompositeMode?, dialogTag: String?) {
if (StateKeeper.currentFragment is SimpleFilePickerDialog.InteractionListenerString)
return (StateKeeper.currentFragment as SimpleFilePickerDialog.InteractionListenerString).showListItemDialog(title, folderPath, mode, dialogTag)
}
abstract fun goToNewFragment(fragment: WizardFragment)
open fun onCheckBoxClicked(view: View) {

View File

@ -46,7 +46,7 @@ class ConfirmInfoFragment : WizardFragment() {
view.confirm_sel_method.text = when (StateKeeper.flashMethod) {
FlashMethod.FLASH_API -> getString(R.string.flash_dd_usb_api)
FlashMethod.FLASH_DD -> getString(R.string.flash_dd_root)
FlashMethod.FLASH_DMG_API -> getString(R.string.flash_dmg_api)
FlashMethod.FLASH_UNETBOOTIN -> getString(R.string.flash_unetbootin)
FlashMethod.FLASH_WOEUSB -> getString(R.string.flash_woeusb)
else -> null

View File

@ -33,8 +33,8 @@ class FlashMethodFragment : WizardFragment() {
override fun onRadioButtonClicked(view: View) {
StateKeeper.flashMethod = when (view.id) {
R.id.flash_dd_root_radio -> FlashMethod.FLASH_DD
R.id.flash_dd_usb_api_radio -> FlashMethod.FLASH_API
R.id.flash_dmg_api_radio -> FlashMethod.FLASH_DMG_API
R.id.flash_usb_api_radio -> FlashMethod.FLASH_API
R.id.flash_unetbootin_radio -> FlashMethod.FLASH_UNETBOOTIN
R.id.flash_woeusb_radio -> FlashMethod.FLASH_WOEUSB
else -> null

View File

@ -6,13 +6,14 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.os.Environment
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.github.isabsent.filepicker.SimpleFilePickerDialog
import eu.depau.etchdroid.R
import eu.depau.etchdroid.StateKeeper
import eu.depau.etchdroid.abc.WizardActivity
@ -24,21 +25,23 @@ import eu.depau.etchdroid.values.ImageLocation
import eu.depau.etchdroid.values.WizardStep
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.fragment_select_location.*
import kotlinx.android.synthetic.main.wizard_fragment_layout.*
import java.io.File
/**
* A placeholder fragment containing a simple view.
*/
class ImageLocationFragment : WizardFragment() {
class ImageLocationFragment : WizardFragment(), SimpleFilePickerDialog.InteractionListenerString {
val READ_REQUEST_CODE = 42
val MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 29
val MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 29
val TAG = "ImageLocationFragment"
val PICKER_DIALOG_TAG = "eu.depau.etchdroid.filepicker.DIALOG_TAG"
fun isStreamingAvailable(): Boolean {
if (StateKeeper.imageLocation != ImageLocation.REMOTE)
return false
if (StateKeeper.flashMethod != FlashMethod.FLASH_DD && StateKeeper.flashMethod != FlashMethod.FLASH_API)
if (StateKeeper.flashMethod != FlashMethod.FLASH_DMG_API && StateKeeper.flashMethod != FlashMethod.FLASH_API)
return false
return true
}
@ -83,13 +86,46 @@ class ImageLocationFragment : WizardFragment() {
override fun onButtonClicked(view: View) {
if (view.id == R.id.pick_file_btn) {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.setType("*/*");
activity?.startActivityForResult(intent, READ_REQUEST_CODE)
when (StateKeeper.flashMethod) {
FlashMethod.FLASH_API -> {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.setType("*/*");
activity?.startActivityForResult(intent, READ_REQUEST_CODE)
}
FlashMethod.FLASH_DMG_API -> {
if (checkAndRequestStorageReadPerm()) {
val sdcard = Environment.getExternalStorageDirectory().absolutePath
showListItemDialog("Select a DMG file", sdcard, SimpleFilePickerDialog.CompositeMode.FILE_ONLY_DIRECT_CHOICE_IMMEDIATE, PICKER_DIALOG_TAG)
}
}
FlashMethod.FLASH_UNETBOOTIN -> {
}
FlashMethod.FLASH_WOEUSB -> {
}
null -> {
}
}
}
}
fun checkAndRequestStorageReadPerm(): Boolean {
if ((ContextCompat.checkSelfPermission(activity!!, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity!!,
Manifest.permission.READ_EXTERNAL_STORAGE)) {
view!!.snackbar("Storage permission is required to read DMG images")
} else {
ActivityCompat.requestPermissions(activity!!,
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE)
}
} else {
// Permission granted
return true
}
return false
}
override fun nextStep(view: View?) {
if (StateKeeper.imageLocation == null) {
view?.snackbar(getString(R.string.select_image_location))
@ -112,16 +148,16 @@ class ImageLocationFragment : WizardFragment() {
}
if (StateKeeper.imageLocation == ImageLocation.REMOTE && !StateKeeper.streamingWrite) {
// Request permission to download file
if (ContextCompat.checkSelfPermission(activity!!, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
ActivityCompat.requestPermissions(activity!!,
arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE)
return
}
// // Request permission to download file
// if (ContextCompat.checkSelfPermission(activity!!, Manifest.permission.WRITE_EXTERNAL_STORAGE)
// != PackageManager.PERMISSION_GRANTED) {
//
// // Permission is not granted
// ActivityCompat.requestPermissions(activity!!,
// arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
// MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE)
// return
// }
}
@ -130,13 +166,14 @@ class ImageLocationFragment : WizardFragment() {
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
MY_PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE -> {
// If request is cancelled, the result arrays are empty.
if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
nextStep(fragment_layout)
} else {
Snackbar.make(fragment_layout, getString(R.string.storage_perm_required_explaination), Snackbar.LENGTH_LONG).show()
}
MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE -> {
onButtonClicked(pick_file_btn)
// // If request is cancelled, the result arrays are empty.
// if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
// nextStep(fragment_layout)
// } else {
// Snackbar.make(fragment_layout, getString(R.string.storage_perm_required_explaination), Snackbar.LENGTH_LONG).show()
// }
return
}
@ -190,6 +227,27 @@ class ImageLocationFragment : WizardFragment() {
updateFileButtonLabel(activity as WizardActivity)
}
}
}
override fun onResult(dialogTag: String, which: Int, extras: Bundle): Boolean {
when (dialogTag) {
PICKER_DIALOG_TAG -> {
if (extras.containsKey(SimpleFilePickerDialog.SELECTED_SINGLE_PATH)) {
val path = extras.getString(SimpleFilePickerDialog.SELECTED_SINGLE_PATH)
StateKeeper.imageFile = Uri.fromFile(File(path))
updateFileButtonLabel(activity as WizardActivity)
}
}
}
return false
}
override fun showListItemDialog(title: String?, folderPath: String?, mode: SimpleFilePickerDialog.CompositeMode?, dialogTag: String?) {
SimpleFilePickerDialog.build(folderPath, mode)
.title(title)
.filterable(true, true)
.show(this, dialogTag)
}
}

View File

@ -2,7 +2,7 @@ package eu.depau.etchdroid.values
enum class FlashMethod {
FLASH_API,
FLASH_DD,
FLASH_DMG_API,
FLASH_UNETBOOTIN,
FLASH_WOEUSB
}

View File

@ -13,19 +13,18 @@
android:layout_height="wrap_content">
<RadioButton
android:id="@+id/flash_dd_usb_api_radio"
android:id="@+id/flash_usb_api_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onRadioButtonClicked"
android:text="@string/flash_dd_usb_api"/>
<RadioButton
android:id="@+id/flash_dd_root_radio"
android:id="@+id/flash_dmg_api_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
android:onClick="onRadioButtonClicked"
android:text="@string/flash_dd_root"/>
android:text="@string/flash_dmg_api"/>
<RadioButton
android:id="@+id/flash_unetbootin_radio"

View File

@ -4,7 +4,7 @@
<string name="download_image_from_url">Download image from URL</string>
<string name="use_local_image">Use local image</string>
<string name="flash_dd_usb_api">Write image directly to disk (using Android API)</string>
<string name="flash_dd_root">Write using dd (requires root)</string>
<string name="flash_dmg_api">Restore macOS DMG image to disk (using Android API)</string>
<string name="flash_unetbootin">Unetbootin-style flash (MBR only, requires root)</string>
<string name="flash_woeusb">Write Windows image (using WoeUSB, requires root)</string>
<string name="download_streaming">Stream directly to USB drive</string>