Show DMG partition table in image picker screen

This commit is contained in:
Davide Depau 2018-08-17 02:43:58 +02:00
parent 8cba765dff
commit e538047399
Signed by: depau
GPG key ID: C7D999B6A55EFE86
14 changed files with 325 additions and 66 deletions

View file

@ -30,6 +30,7 @@ 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.android.support:gridlayout-v7:28.0.0-rc01'
implementation 'com.github.isabsent:filepicker:1.1.01'
// implementation 'com.github.mjdev:libaums:0.5.5'

View file

@ -13,7 +13,7 @@ object StateKeeper {
var wizardStep: WizardStep = WizardStep.SELECT_FLASH_METHOD
var currentFragment: WizardFragment? = null
var flashMethod: FlashMethod? = null
var imageLocation: ImageLocation? = null
var imageLocation: ImageLocation? = ImageLocation.LOCAL
var streamingWrite: Boolean = false
var imageFile: Uri? = null
var imageRepr: Image? = null

View file

@ -0,0 +1,76 @@
package eu.depau.etchdroid.adapters
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.LinearLayout
import eu.depau.etchdroid.R
import eu.depau.etchdroid.kotlin_exts.toHRSize
import eu.depau.etchdroid.utils.Partition
import kotlinx.android.synthetic.main.part_data_keyvalue.view.*
import kotlinx.android.synthetic.main.partition_row.view.*
class PartitionTableRecyclerViewAdapter(private val dataset: List<Partition>) : RecyclerView.Adapter<PartitionTableRecyclerViewAdapter.ViewHolder>() {
class ViewHolder(val layout: LinearLayout) : RecyclerView.ViewHolder(layout)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int):
ViewHolder {
val layout = LayoutInflater.from(parent.context)
.inflate(R.layout.partition_row, parent, false) as LinearLayout
return ViewHolder(layout)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val part = dataset[position]
val layout = holder.layout
val li = LayoutInflater.from(layout.context)
var kv: LinearLayout
layout.part_number.text = "${part.number}"
layout.part_data_grid.removeAllViewsInLayout()
if (part.partLabel != null) {
kv = li.inflate(R.layout.part_data_keyvalue, layout.part_data_grid, false) as LinearLayout
kv.key.text = layout.context.getString(R.string.part_label)
kv.value.text = part.partLabel
layout.part_data_grid.addView(kv)
}
if (part.fsLabel != null) {
kv = li.inflate(R.layout.part_data_keyvalue, layout.part_data_grid, false) as LinearLayout
kv.key.text = layout.context.getString(R.string.fs_label)
kv.value.text = part.fsLabel
layout.part_data_grid.addView(kv)
}
if (part.fsType != null) {
kv = li.inflate(R.layout.part_data_keyvalue, layout.part_data_grid, false) as LinearLayout
kv.key.text = layout.context.getString(R.string.fs_type)
kv.value.text = part.fsType.getString(layout.context)
layout.part_data_grid.addView(kv)
}
if (part.fsLabel != null) {
kv = li.inflate(R.layout.part_data_keyvalue, layout.part_data_grid, false) as LinearLayout
kv.key.text = layout.context.getString(R.string.fs_label)
kv.value.text = part.fsLabel
layout.part_data_grid.addView(kv)
}
if (part.size != null) {
kv = li.inflate(R.layout.part_data_keyvalue, layout.part_data_grid, false) as LinearLayout
kv.key.text = layout.context.getString(R.string.part_size)
kv.value.text = part.size.toHRSize()
layout.part_data_grid.addView(kv)
}
}
override fun getItemCount(): Int = dataset.size
fun get(position: Int): Partition {
return dataset[position]
}
}

View file

@ -1,5 +1,8 @@
package eu.depau.etchdroid.enums
import android.content.Context
import eu.depau.etchdroid.R
enum class FilesystemType {
// Microsoft
FAT12,
@ -35,5 +38,35 @@ enum class FilesystemType {
FREE,
UNFORMATTED,
UNKNOWN
UNKNOWN;
fun getString(context: Context): String {
return when(this) {
FilesystemType.FAT12 -> context.getString(R.string.fs_fat12)
FilesystemType.FAT16 -> context.getString(R.string.fs_fat16)
FilesystemType.FAT32 -> context.getString(R.string.fs_fat32)
FilesystemType.EXFAT -> context.getString(R.string.fs_exfat)
FilesystemType.NTFS -> context.getString(R.string.fs_ntfs)
FilesystemType.REFS -> context.getString(R.string.fs_refs)
FilesystemType.HFS -> context.getString(R.string.fs_hfs)
FilesystemType.HFSPLUS -> context.getString(R.string.fs_hfsplus)
FilesystemType.APFS -> context.getString(R.string.fs_apfs)
FilesystemType.APT_DATA -> context.getString(R.string.fs_apt_data)
FilesystemType.ISO9660 -> context.getString(R.string.fs_iso9660)
FilesystemType.EXT2 -> context.getString(R.string.fs_ext2)
FilesystemType.EXT3 -> context.getString(R.string.fs_ext3)
FilesystemType.EXT4 -> context.getString(R.string.fs_ext4)
FilesystemType.BTRFS -> context.getString(R.string.fs_btrfs)
FilesystemType.F2FS -> context.getString(R.string.fs_f2fs)
FilesystemType.LUKS -> context.getString(R.string.fs_luks)
FilesystemType.LINUX_SWAP -> context.getString(R.string.fs_linux_swap)
FilesystemType.LINUX_LVM_PV -> context.getString(R.string.fs_linux_lvm_pv)
FilesystemType.UFS -> context.getString(R.string.fs_ufs)
FilesystemType.XFS -> context.getString(R.string.fs_xfs)
FilesystemType.ZFS -> context.getString(R.string.fs_zfs)
FilesystemType.FREE -> context.getString(R.string.fs_free)
FilesystemType.UNFORMATTED -> context.getString(R.string.fs_unformatted)
FilesystemType.UNKNOWN -> context.getString(R.string.fs_unknown)
}
}
}

View file

@ -1,5 +1,8 @@
package eu.depau.etchdroid.enums
import android.content.Context
import eu.depau.etchdroid.R
enum class PartitionTableType {
AIX,
AMIGA,
@ -10,5 +13,20 @@ enum class PartitionTableType {
MAC,
MSDOS,
PC98,
SUN
}
SUN;
fun getString(context: Context): String {
return when(this) {
PartitionTableType.AIX -> context.getString(R.string.ptt_aix)
PartitionTableType.AMIGA -> context.getString(R.string.ptt_amiga)
PartitionTableType.BSD -> context.getString(R.string.ptt_bsd)
PartitionTableType.DVH -> context.getString(R.string.ptt_dvh)
PartitionTableType.GPT -> context.getString(R.string.ptt_gpt)
PartitionTableType.LOOP -> context.getString(R.string.ptt_loop)
PartitionTableType.MAC -> context.getString(R.string.ptt_mac)
PartitionTableType.MSDOS -> context.getString(R.string.ptt_msdos)
PartitionTableType.PC98 -> context.getString(R.string.ptt_pc98)
PartitionTableType.SUN -> context.getString(R.string.ptt_sun)
}
}
}

View file

@ -9,6 +9,7 @@ import android.os.Bundle
import android.os.Environment
import android.support.v4.app.ActivityCompat
import android.support.v4.content.ContextCompat
import android.support.v7.widget.LinearLayoutManager
import android.util.Log
import android.view.LayoutInflater
import android.view.View
@ -17,6 +18,7 @@ import com.github.isabsent.filepicker.SimpleFilePickerDialog
import eu.depau.etchdroid.R
import eu.depau.etchdroid.StateKeeper
import eu.depau.etchdroid.activities.WizardActivity
import eu.depau.etchdroid.adapters.PartitionTableRecyclerViewAdapter
import eu.depau.etchdroid.kotlin_exts.getFileName
import eu.depau.etchdroid.kotlin_exts.snackbar
import eu.depau.etchdroid.enums.FlashMethod
@ -37,6 +39,7 @@ class ImageLocationFragment : WizardFragment(), SimpleFilePickerDialog.Interacti
val MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 29
val TAG = "ImageLocationFragment"
val PICKER_DIALOG_TAG = "eu.depau.etchdroid.filepicker.DIALOG_TAG"
var issuesFound = false
fun isStreamingAvailable(): Boolean {
if (StateKeeper.imageLocation != ImageLocation.REMOTE)
@ -46,7 +49,7 @@ class ImageLocationFragment : WizardFragment(), SimpleFilePickerDialog.Interacti
return true
}
fun setStreamingCheckBoxAvailability(context: WizardActivity) {
/* fun setStreamingCheckBoxAvailability(context: WizardActivity) {
val checkBox = streaming_write_checkbox
if (checkBox == null)
@ -59,28 +62,29 @@ class ImageLocationFragment : WizardFragment(), SimpleFilePickerDialog.Interacti
checkBox.isEnabled = enabled
onCheckBoxClicked(checkBox)
}
}
}*/
override fun onCheckBoxClicked(view: View) {
/* override fun onCheckBoxClicked(view: View) {
super.onCheckBoxClicked(view)
if (view.id == R.id.streaming_write_checkbox)
StateKeeper.streamingWrite = view.isActivated && view.isEnabled
}
}*/
override fun onRadioButtonClicked(view: View) {
StateKeeper.imageLocation = when (view.id) {
StateKeeper.imageLocation = ImageLocation.LOCAL
/*when (view.id) {
R.id.download_img_radio -> ImageLocation.REMOTE
R.id.use_local_img_radio -> ImageLocation.LOCAL
else -> null
}
}*/
fab?.show()
pick_file_btn?.isEnabled = StateKeeper.imageLocation == ImageLocation.LOCAL
img_url_textview?.isEnabled = StateKeeper.imageLocation == ImageLocation.REMOTE
// img_url_textview?.isEnabled = StateKeeper.imageLocation == ImageLocation.REMOTE
setStreamingCheckBoxAvailability(activity as WizardActivity)
// setStreamingCheckBoxAvailability(activity as WizardActivity)
loadImageChanges(activity as WizardActivity)
}
@ -127,12 +131,17 @@ class ImageLocationFragment : WizardFragment(), SimpleFilePickerDialog.Interacti
}
override fun nextStep(view: View?) {
if (issuesFound) {
view?.snackbar(getString(R.string.issues_found_expl))
return
}
if (StateKeeper.imageLocation == null) {
view?.snackbar(getString(R.string.select_image_location))
return
}
if (StateKeeper.imageLocation == ImageLocation.REMOTE) {
/* if (StateKeeper.imageLocation == ImageLocation.REMOTE) {
try {
StateKeeper.imageFile = getRemoteImageUri(activity as WizardActivity)
} catch (e: RuntimeException) {
@ -140,7 +149,7 @@ class ImageLocationFragment : WizardFragment(), SimpleFilePickerDialog.Interacti
view?.snackbar(getString(R.string.provided_url_invalid))
return
}
}
}*/
if (StateKeeper.imageFile == null) {
view?.snackbar(getString(R.string.provide_image_file))
@ -185,7 +194,7 @@ class ImageLocationFragment : WizardFragment(), SimpleFilePickerDialog.Interacti
override fun onFragmentAdded(activity: WizardActivity) {
super.onFragmentAdded(activity)
setStreamingCheckBoxAvailability(activity)
// setStreamingCheckBoxAvailability(activity)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
@ -196,10 +205,10 @@ class ImageLocationFragment : WizardFragment(), SimpleFilePickerDialog.Interacti
return inflater.inflate(R.layout.fragment_select_location, container, false)
}
fun getRemoteImageUri(context: WizardActivity): Uri {
/* fun getRemoteImageUri(context: WizardActivity): Uri {
val text = img_url_textview.text.toString()
return Uri.parse(text)
}
}*/
fun loadImageChanges(context: WizardActivity) {
val button = pick_file_btn
@ -214,7 +223,24 @@ class ImageLocationFragment : WizardFragment(), SimpleFilePickerDialog.Interacti
if (StateKeeper.flashMethod == FlashMethod.FLASH_DMG_API) {
StateKeeper.imageRepr = DMGImage(uri, context)
Log.d(TAG, (StateKeeper.imageRepr as DMGImage).partitionTable.toString())
val imgRepr = StateKeeper.imageRepr as DMGImage
if (imgRepr.tableType == null && (imgRepr.partitionTable == null || imgRepr.partitionTable?.size == 0)) {
part_table_header.text = getString(R.string.image_is_not_dmg)
issuesFound = true
return
} else {
part_table_header.text = if (imgRepr.tableType != null) "Partition table:" else ""
part_table_header_side.text = imgRepr.tableType?.getString(context) ?: ""
issuesFound = false
val viewAdapter = PartitionTableRecyclerViewAdapter(imgRepr.partitionTable!!)
part_table_recycler.apply {
setHasFixedSize(true)
layoutManager = LinearLayoutManager(activity)
adapter = viewAdapter
}
}
}
}

View file

@ -16,10 +16,10 @@
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
android:paddingBottom="@dimen/row_padding_vertical"
android:paddingBottom="@dimen/row_padding"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/row_padding_vertical">
android:paddingTop="@dimen/row_padding">
<TextView
android:id="@+id/confirm_sel_method_title"
@ -46,10 +46,10 @@
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
android:paddingBottom="@dimen/row_padding_vertical"
android:paddingBottom="@dimen/row_padding"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/row_padding_vertical">
android:paddingTop="@dimen/row_padding">
<TextView
android:id="@+id/confirm_sel_image_title"
@ -85,10 +85,10 @@
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
android:paddingBottom="@dimen/row_padding_vertical"
android:paddingBottom="@dimen/row_padding"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/row_padding_vertical">
android:paddingTop="@dimen/row_padding">
<TextView
android:id="@+id/confirm_sel_usbdev_title"
@ -124,10 +124,10 @@
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
android:paddingBottom="@dimen/row_padding_vertical"
android:paddingBottom="@dimen/row_padding"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/row_padding_vertical">
android:paddingTop="@dimen/row_padding">
<TextView
android:id="@+id/confirm_extra_info"

View file

@ -5,52 +5,55 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".fragments.FlashMethodFragment"
tools:showIn="@layout/activity_main">
tools:context=".fragments.FlashMethodFragment">
<RadioGroup
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RadioButton
android:id="@+id/use_local_img_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onRadioButtonClicked"
android:text="@string/use_local_image"/>
<Button
android:id="@+id/pick_file_btn"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
android:onClick="onButtonClicked"
android:text="@string/pick_a_file"/>
<RadioButton
android:id="@+id/download_img_radio"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
android:onClick="onRadioButtonClicked"
android:text="@string/download_image_from_url"/>
<EditText
android:id="@+id/img_url_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:enabled="false"
android:hint="@string/image_url_hint"
android:inputType="textUri"/>
<CheckBox
android:id="@+id/streaming_write_checkbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="false"
android:enabled="false"
android:onClick="onCheckBoxClicked"
android:text="@string/download_streaming"/>
</RadioGroup>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:paddingBottom="@dimen/row_padding"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/row_padding">
<TextView
android:id="@+id/part_table_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/grid_padding"
android:textColor="@color/name"
android:textSize="16sp"
android:textStyle="bold"/>
<TextView
android:id="@+id/part_table_header_side"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/grid_padding"
android:textColor="@color/info"/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/part_table_recycler"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View file

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:grid="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:id="@+id/key"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:textColor="@color/name"
android:textSize="16sp"
android:textStyle="bold"
android:paddingStart="@dimen/grid_padding"
android:paddingEnd="@dimen/grid_padding"/>
<TextView
android:id="@+id/value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="@dimen/grid_padding"
android:paddingEnd="@dimen/grid_padding"/>
</LinearLayout>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:grid="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:clickable="true"
android:focusable="true"
android:orientation="horizontal"
android:paddingBottom="@dimen/row_padding"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/row_padding">
<TextView
android:id="@+id/part_number"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="@dimen/grid_padding"/>
<LinearLayout
android:id="@+id/part_data_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="@dimen/row_padding"
android:paddingEnd="@dimen/row_padding"
android:orientation="vertical">
</LinearLayout>
</LinearLayout>

View file

@ -6,10 +6,10 @@
android:clickable="true"
android:focusable="true"
android:orientation="vertical"
android:paddingBottom="@dimen/row_padding_vertical"
android:paddingBottom="@dimen/row_padding"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/row_padding_vertical">
android:paddingTop="@dimen/row_padding">
<TextView
android:id="@+id/name"

View file

@ -2,5 +2,6 @@
<dimen name="fab_margin">16dp</dimen>
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="row_padding_vertical">10dp</dimen>
<dimen name="row_padding">10dp</dimen>
<dimen name="grid_padding">5dp</dimen>
</resources>

View file

@ -8,7 +8,7 @@
<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>
<string name="pick_a_file">Pick a file</string>
<string name="pick_a_file">Pick an image file</string>
<string name="image_url_hint">Image URL</string>
<string name="provided_url_invalid">Provided URL is invalid</string>
<string name="select_image_location">Please select image location</string>
@ -29,4 +29,46 @@
<string name="notchan_writestatus_desc">Used to display the status of images being written to USB drives</string>
<string name="notif_initializing">Initializing...</string>
<string name="notif_writing_img">Writing image</string>
<string name="issues_found_expl">Selected image cannot be flashed</string>
<string name="image_is_not_dmg">Selected image is not a DMG image (maybe it\'s corrupted)</string>
<string name="ptt_aix">IBM AIX</string>
<string name="ptt_amiga">AMIGA</string>
<string name="ptt_bsd">BSD</string>
<string name="ptt_dvh">DVH</string>
<string name="ptt_gpt">GPT</string>
<string name="ptt_loop">None</string>
<string name="ptt_mac">APT</string>
<string name="ptt_msdos">MBR</string>
<string name="ptt_pc98">PC98</string>
<string name="ptt_sun">Sun</string>
<string name="fs_fat12">FAT12</string>
<string name="fs_fat16">FAT16</string>
<string name="fs_fat32">FAT32</string>
<string name="fs_exfat">ExFAT</string>
<string name="fs_ntfs">NTFS</string>
<string name="fs_refs">ReFS</string>
<string name="fs_hfs">HFS</string>
<string name="fs_hfsplus">HFS+</string>
<string name="fs_apfs">APFS</string>
<string name="fs_apt_data">APT data</string>
<string name="fs_iso9660">ISO 9660</string>
<string name="fs_ext2">Linux Ext2</string>
<string name="fs_ext3">Linux Ext3</string>
<string name="fs_ext4">Linux Ext4</string>
<string name="fs_btrfs">Btrfs</string>
<string name="fs_f2fs">f2fs</string>
<string name="fs_luks">LUKS</string>
<string name="fs_linux_swap">Linux swap</string>
<string name="fs_linux_lvm_pv">Linux LVM2 PV</string>
<string name="fs_ufs">UFS</string>
<string name="fs_xfs">XFS</string>
<string name="fs_zfs">ZFS</string>
<string name="fs_free">Free space</string>
<string name="fs_unformatted">Unformatted</string>
<string name="fs_unknown">Unknown</string>
<string name="part_name">Name:</string>
<string name="part_label">Name</string>
<string name="fs_label">Label</string>
<string name="fs_type">Type</string>
<string name="part_size">Size</string>
</resources>

View file

@ -1,11 +1,13 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<style name="AppTheme" parent="Base.Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="coordinatorLayoutStyle">@style/Widget.Support.CoordinatorLayout</item>
<item name="floatingActionButtonStyle">@style/Widget.Design.FloatingActionButton</item>
</style>
<style name="AppTheme.NoActionBar">