SubwayTooter-Android-App/app/src/main/java/jp/juggler/subwaytooter/actmain/ActMainImportData.kt

151 lines
5.5 KiB
Kotlin

package jp.juggler.subwaytooter.actmain
import android.net.Uri
import android.os.Process
import android.util.JsonReader
import android.view.WindowManager
import androidx.annotation.WorkerThread
import jp.juggler.subwaytooter.ActMain
import jp.juggler.subwaytooter.R
import jp.juggler.subwaytooter.appsetting.AppDataExporter
import jp.juggler.subwaytooter.column.Column
import jp.juggler.subwaytooter.notification.setImportProtector
import jp.juggler.util.coroutine.launchProgress
import jp.juggler.util.coroutine.runOnMainLooper
import jp.juggler.util.log.LogCategory
import jp.juggler.util.log.showToast
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.InputStreamReader
import java.util.zip.ZipInputStream
private val log = LogCategory("ActMainImportAppData")
@WorkerThread
fun ActMain.importAppData(uri: Uri) {
// remove all columns
phoneOnly { env -> env.pager.adapter = null }
appState.editColumnList(save = false) { list ->
list.forEach { it.dispose() }
list.clear()
}
phoneTab(
{ env -> env.pager.adapter = env.pagerAdapter },
{ env -> resizeColumnWidth(env) }
)
updateColumnStrip()
launchProgress(
"importing app data",
doInBackground = { progress ->
fun setProgressMessage(sv: String) = runOnMainLooper { progress.setMessageEx(sv) }
setProgressMessage("import data to local storage...")
// アプリ内領域に一時ファイルを作ってコピーする
val cacheDir = cacheDir
cacheDir.mkdir()
val file = File(cacheDir, "SubwayTooter.${Process.myPid()}.${Process.myTid()}.tmp")
val copyBytes = contentResolver.openInputStream(uri)?.use { inStream ->
FileOutputStream(file).use { outStream ->
inStream.copyTo(outStream)
}
}
if (copyBytes == null) {
showToast(true, "openInputStream failed.")
return@launchProgress null
}
// 通知サービスを止める
setProgressMessage("syncing notification poller…")
setImportProtector(this@importAppData, true)
// データを読み込む
setProgressMessage("reading app data...")
var newColumnList: ArrayList<Column>? = null
var zipEntryCount = 0
try {
ZipInputStream(FileInputStream(file)).use { zipStream ->
while (true) {
val entry = zipStream.nextEntry ?: break
++zipEntryCount
try {
//
val entryName = entry.name
if (entryName.endsWith(".json")) {
newColumnList = AppDataExporter.decodeAppData(
this@importAppData,
JsonReader(InputStreamReader(zipStream, "UTF-8"))
)
continue
}
if (AppDataExporter.restoreBackgroundImage(
this@importAppData,
newColumnList,
zipStream,
entryName
)
) {
continue
}
} finally {
zipStream.closeEntry()
}
}
}
} catch (ex: Throwable) {
if (zipEntryCount != 0) {
log.e(ex, "importAppData failed.")
showToast(ex, "importAppData failed.")
}
}
// zipではなかった場合、zipEntryがない状態になる。例外はPH-1では出なかったが、出ても問題ないようにする。
if (zipEntryCount == 0) {
InputStreamReader(FileInputStream(file), "UTF-8").use { inStream ->
newColumnList =
AppDataExporter.decodeAppData(this@importAppData, JsonReader(inStream))
}
}
newColumnList
},
afterProc = {
// cancelled.
if (it == null) return@launchProgress
try {
phoneOnly { env -> env.pager.adapter = null }
appState.editColumnList { list ->
list.clear()
list.addAll(it)
}
phoneTab(
{ env -> env.pager.adapter = env.pagerAdapter },
{ env -> resizeColumnWidth(env) }
)
updateColumnStrip()
} finally {
// 通知サービスをリスタート
setImportProtector(this@importAppData, false)
}
showToast(true, R.string.import_completed_please_restart_app)
finish()
},
preProc = {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
},
postProc = {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
)
}