Enable DMG file selection
This commit is contained in:
parent
9b12ebf8b1
commit
c5fae3d869
8 changed files with 110 additions and 36 deletions
|
@ -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'
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package eu.depau.etchdroid.values
|
|||
|
||||
enum class FlashMethod {
|
||||
FLASH_API,
|
||||
FLASH_DD,
|
||||
FLASH_DMG_API,
|
||||
FLASH_UNETBOOTIN,
|
||||
FLASH_WOEUSB
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue