diff --git a/app/src/main/java/config/BuildVariant.kt b/app/src/main/java/config/BuildVariant.kt index d9c9f09..3361ea8 100644 --- a/app/src/main/java/config/BuildVariant.kt +++ b/app/src/main/java/config/BuildVariant.kt @@ -3,7 +3,5 @@ package config object BuildVariant { const val DATA_PROVIDER_AUTHORITY = "jp.juggler.fadownloader.data" const val FILE_PROVIDER_AUTHORITY = "jp.juggler.fadownloader.FileProvider" - - const val AD_FREE = false } diff --git a/app/src/main/java/jp/juggler/fadownloader/ActMain.kt b/app/src/main/java/jp/juggler/fadownloader/ActMain.kt index 39a0cb5..9041e1a 100644 --- a/app/src/main/java/jp/juggler/fadownloader/ActMain.kt +++ b/app/src/main/java/jp/juggler/fadownloader/ActMain.kt @@ -7,6 +7,7 @@ import android.app.Dialog import android.content.Context import android.content.Intent import android.content.IntentSender +import android.content.SharedPreferences import android.net.Uri import android.os.Build import android.os.Bundle @@ -17,7 +18,6 @@ import android.support.v4.provider.DocumentFile import android.support.v4.view.ViewPager import android.support.v7.app.AlertDialog import android.support.v7.app.AppCompatActivity -import android.text.TextUtils import android.view.* import android.widget.TextView import com.example.android.trivialdrivesample.util.IabHelper @@ -28,7 +28,6 @@ import com.google.android.gms.common.api.ApiException import com.google.android.gms.common.api.ResolvableApiException import com.google.android.gms.location.* import com.google.android.gms.tasks.OnCompleteListener -import config.BuildVariant import jp.juggler.fadownloader.model.LocalFile import jp.juggler.fadownloader.picker.FolderPicker import jp.juggler.fadownloader.picker.SSIDPicker @@ -61,6 +60,8 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { internal const val REMOVE_AD_PRODUCT_ID = "remove_ad" } + internal lateinit var pref : SharedPreferences + internal lateinit var tvStatus : TextView internal lateinit var handler : Handler @@ -81,69 +82,77 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { ///////////////////////////////////////////////////////////////////////// // アプリ権限の要求 - private val location_setting_callback2 :OnCompleteListener = OnCompleteListener{ task-> - try { - task.getResult(ApiException::class.java) - // All location settings are satisfied. - // The client can initialize location requests here. - startDownloadService() - } catch (apiException: ApiException) { - when(apiException.statusCode) { - LocationSettingsStatusCodes.RESOLUTION_REQUIRED->{ - - if(Build.VERSION.SDK_INT <= 17) { - - // SH-02E(4.1.2),F10d(4.2.2)などで - // Wi-Fiが無効だと RESOLUTION_REQUIRED を返すが、 - // STAモード前提だとWi-FiはOFFで正しい - // startResolutionForResult で表示されるダイアログで - // OKしてもキャンセルしても戻るボタンを押してもresultCodeが0を返す - // ていうかGeoTagging modeをOFF以外のどれにしてもWi-FiをONにしろと警告が出る - // これなら何もチェックせずにサービスを開始した方がマシ - // なお、4.3のGalaxy Nexus ではこの問題は起きなかった - - startDownloadService() + private val location_setting_callback2 : OnCompleteListener = + OnCompleteListener { task -> + try { + task.getResult(ApiException::class.java) + // All location settings are satisfied. + // The client can initialize location requests here. + startDownloadService() + } catch(apiException : ApiException) { + when(apiException.statusCode) { + LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> { - } else { - // Location settings are not satisfied. - // But could be fixed by showing the user a dialog. - try { - if( apiException !is ResolvableApiException){ - // should not happen - }else{ - // Show the dialog by calling startResolutionForResult(), - // and check the result in onActivityResult(). - apiException.startResolutionForResult( this@ActMain, REQUEST_RESOLUTION) + if(Build.VERSION.SDK_INT <= 17) { + + // SH-02E(4.1.2),F10d(4.2.2)などで + // Wi-Fiが無効だと RESOLUTION_REQUIRED を返すが、 + // STAモード前提だとWi-FiはOFFで正しい + // startResolutionForResult で表示されるダイアログで + // OKしてもキャンセルしても戻るボタンを押してもresultCodeが0を返す + // ていうかGeoTagging modeをOFF以外のどれにしてもWi-FiをONにしろと警告が出る + // これなら何もチェックせずにサービスを開始した方がマシ + // なお、4.3のGalaxy Nexus ではこの問題は起きなかった + + startDownloadService() + + } else { + // Location settings are not satisfied. + // But could be fixed by showing the user a dialog. + try { + if(apiException !is ResolvableApiException) { + // should not happen + } else { + // Show the dialog by calling startResolutionForResult(), + // and check the result in onActivityResult(). + apiException.startResolutionForResult( + this@ActMain, + REQUEST_RESOLUTION + ) + } + } catch(ex : IntentSender.SendIntentException) { + log.trace(ex, "resolution_request_failed") + Utils.showToast( + this@ActMain, + true, + R.string.resolution_request_failed + ) } - } catch ( ex: IntentSender.SendIntentException ) { - log.trace(ex,"resolution_request_failed") - Utils.showToast(this@ActMain, true, R.string.resolution_request_failed) + } - } - } - - LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE ->{ - // Location settings are not satisfied. - // However, we have no way to fix the settings so we won't show the dialog. - Utils.showToast( - this@ActMain, - true, - R.string.location_setting_change_unavailable - ) - } - - else->{ - Utils.showToast( - this@ActMain, - true, - R.string.location_setting_returns_unknown_status, - apiException.statusCode - ) + + LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> { + // Location settings are not satisfied. + // However, we have no way to fix the settings so we won't show the dialog. + Utils.showToast( + this@ActMain, + true, + R.string.location_setting_change_unavailable + ) + } + + else -> { + Utils.showToast( + this@ActMain, + true, + R.string.location_setting_returns_unknown_status, + apiException.statusCode + ) + } } } } - } private val proc_status : Runnable = object : Runnable { override fun run() { @@ -181,7 +190,7 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { if(mIabHelper == null) return@OnIabPurchaseFinishedListener if(result.isFailure) { - log.e( "onIabPurchaseFinished: ${result.response},${result.message}") + log.e("onIabPurchaseFinished: ${result.response},${result.message}") return@OnIabPurchaseFinishedListener } @@ -229,7 +238,7 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { mAdView !!.pause() } - val e = Pref.pref(this).edit() + val e = pref.edit() e.put(Pref.uiLastPage, pager.currentItem) val page = pager_adapter.getPage(page_idx_setting) @@ -280,92 +289,102 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { } @SuppressLint("NewApi") - public override fun onActivityResult(requestCode : Int, resultCode : Int, resultData : Intent) { - // mIabHelper が結果を処理した - if(mIabHelper != null && mIabHelper !!.handleActivityResult( - requestCode, - resultCode, - resultData - )) return - - if(requestCode == REQUEST_RESOLUTION) { - if(resultCode == Activity.RESULT_OK) { - startDownloadService() - } else { - Utils.showToast(this, true, "resolution request result: %s", resultCode) + public override fun onActivityResult( + requestCode : Int, + resultCode : Int, + resultData : Intent? + ) { + + if(mIabHelper?.handleActivityResult(requestCode, resultCode, resultData) == true) { + // mIabHelper が結果を処理した + return + } + if(requestCode != Activity.RESULT_OK) { + when(requestCode) { + REQUEST_RESOLUTION -> Utils.showToast( + this, + true, + "resolution request result: $resultCode" + ) } - - } else if(requestCode == REQUEST_CODE_DOCUMENT) { - if(resultCode == Activity.RESULT_OK) { - if(Build.VERSION.SDK_INT >= LocalFile.DOCUMENT_FILE_VERSION) { - try { - val treeUri = resultData.data - // 永続的な許可を取得 - contentResolver.takePersistableUriPermission( - treeUri !!, - Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION - ) - // 覚えておく - Pref.pref(this).edit() - .put(Pref.uiFolderUri, treeUri.toString()) - .apply() - } catch(ex : Throwable) { - log.trace(ex,"folder access failed.") + } else if(resultCode == Activity.RESULT_OK) { + when(requestCode) { + REQUEST_RESOLUTION -> startDownloadService() + + REQUEST_CODE_DOCUMENT -> { + if(Build.VERSION.SDK_INT >= LocalFile.DOCUMENT_FILE_VERSION) { + try { + val treeUri = resultData?.data + if(treeUri != null) { + // 永続的な許可を取得 + contentResolver.takePersistableUriPermission( + treeUri, + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION + ) + // 覚えておく + pref.edit() + .put(Pref.uiFolderUri, treeUri.toString()) + .apply() + } + } catch(ex : Throwable) { + log.trace(ex, "folder access failed.") + + Utils.showToast(this, true, ex.withCaption("folder access failed.")) + } - Utils.showToast(this, true,ex.withCaption("folder access failed.")) } - + val page = pager_adapter.getPage(page_idx_setting) + page?.folder_view_update() + return } - } - val page = pager_adapter.getPage(page_idx_setting) - page?.folder_view_update() - return - } else if(requestCode == REQUEST_FOLDER_PICKER) { - if(resultCode == Activity.RESULT_OK) { - try { - val path = resultData.getStringExtra(FolderPicker.EXTRA_FOLDER) - val dummy = - Thread.currentThread().id.toString() + "." + android.os.Process.myPid() - val test_dir = File(File(path), dummy) - - test_dir.mkdir() + + REQUEST_FOLDER_PICKER -> { try { - val test_file = File(test_dir, dummy) - try { - FileOutputStream(test_file).use { fos -> - fos.write("TEST".encodeUTF8() ) + val path = resultData?.getStringExtra(FolderPicker.EXTRA_FOLDER) + if(path != null) { + val dummy = + Thread.currentThread().id.toString() + "." + android.os.Process.myPid() + val test_dir = File(File(path), dummy) + + test_dir.mkdir() + try { + val test_file = File(test_dir, dummy) + try { + FileOutputStream(test_file).use { fos -> + fos.write("TEST".encodeUTF8()) + } + } finally { + test_file.delete() + } + } finally { + test_dir.delete() } - } finally { - test_file.delete() + // 覚えておく + pref.edit() + .put(Pref.uiFolderUri, path) + .apply() } - } finally { - test_dir.delete() + } catch(ex : Throwable) { + log.trace(ex, "folder access failed.") + Utils.showToast(this, true, ex.withCaption("folder access failed.")) } - // 覚えておく - Pref.pref(this).edit() - .put(Pref.uiFolderUri,path) - .apply() - } catch(ex : Throwable) { - log.trace(ex,"folder access failed.") - Utils.showToast(this,true, ex.withCaption( "folder access failed.")) + val page = pager_adapter.getPage(page_idx_setting) + page?.folder_view_update() + return } - } - val page = pager_adapter.getPage(page_idx_setting) - page?.folder_view_update() - return - } else if(requestCode == REQUEST_SSID_PICKER) { - if(resultCode == Activity.RESULT_OK) { - val sv = resultData.getStringExtra(SSIDPicker.EXTRA_SSID) - if(! TextUtils.isEmpty(sv)) { - Pref.pref(this).edit() - .put(Pref.uiSsid,sv) - .apply() + REQUEST_SSID_PICKER -> { + val sv = resultData?.getStringExtra(SSIDPicker.EXTRA_SSID) + if(sv?.isNotEmpty() == true) { + pref.edit() + .put(Pref.uiSsid, sv) + .apply() + } + val page = pager_adapter.getPage(page_idx_setting) + page?.ssid_view_update() + return } } - val page = pager_adapter.getPage(page_idx_setting) - page?.ssid_view_update() - return } super.onActivityResult(requestCode, resultCode, resultData) @@ -374,6 +393,9 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { override fun onCreate(savedInstanceState : Bundle?) { super.onCreate(savedInstanceState) + + this.pref = Pref.pref(this) + setContentView(R.layout.act_main) // ActionBar bar = getSupportActionBar(); @@ -386,7 +408,7 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { setupIabHelper() mAdView = findViewById(R.id.adView) - if(BuildVariant.AD_FREE) { + if(Pref.purchasedRemoveAd(pref)) { (mAdView !!.parent as ViewGroup).removeView(mAdView) mAdView = null } else { @@ -428,7 +450,7 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { PageOther::class.java ) pager.adapter = pager_adapter - pager.currentItem = Pref.uiLastPage( Pref.pref(this) ) + pager.currentItem = Pref.uiLastPage(pref) if(savedInstanceState == null) { @@ -503,7 +525,7 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { // 転送サービスを停止 private fun download_stop_button() { - Pref.pref(this).edit() + pref.edit() .put(Pref.lastMode, Pref.LAST_MODE_STOP) .put(Pref.lastModeUpdate, System.currentTimeMillis()) .apply() @@ -515,7 +537,7 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { val am = getSystemService(Context.ALARM_SERVICE) as? AlarmManager am?.cancel(pi) } catch(ex : Throwable) { - log.trace(ex,"createAlarmPendingIntent failed.") + log.trace(ex, "createAlarmPendingIntent failed.") } } @@ -523,10 +545,10 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { // 転送サービスを開始 private fun download_start_button(repeat : Boolean) { - val e = Pref.pref(this).edit() + val e = pref.edit() //repeat引数の値は、LocationSettingの確認が終わるまで覚えておく必要がある - e.put(Pref.uiRepeat,repeat) + e.put(Pref.uiRepeat, repeat) // UIフォームの値を設定に保存 val page = pager_adapter.getPage(page_idx_setting) @@ -536,10 +558,10 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { when { // 位置情報を使わないオプションの時はLocationSettingをチェックしない - Pref.uiLocationMode(Pref.pref(this)) == LocationTracker.NO_LOCATION_UPDATE -> + Pref.uiLocationMode(pref) == LocationTracker.NO_LOCATION_UPDATE -> startDownloadService() - - else-> startLocationSettingCheck() + + else -> startLocationSettingCheck() } } @@ -562,7 +584,6 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { } private fun startDownloadService() { - val pref = Pref.pref(this) // LocationSettingを確認する前のrepeat引数の値を思い出す val repeat = Pref.uiRepeat(pref) @@ -600,14 +621,14 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { return } - val interval = Pref.uiInterval.getIntOrNull(pref) ?: -1 + val interval = Pref.uiInterval.getIntOrNull(pref) ?: - 1 if(repeat && interval < 1) { Utils.showToast(this, true, getString(R.string.repeat_interval_not_ok)) return } val file_type = Pref.uiFileType(pref).trim() - if(TextUtils.isEmpty(file_type)) { + if(file_type.isEmpty()) { Utils.showToast(this, true, getString(R.string.file_type_empty)) return } @@ -623,22 +644,26 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { if(location_mode != LocationTracker.NO_LOCATION_UPDATE) { - fun x1000(v:Int?) =if(v!=null ){ + fun x1000(v : Int?) = if(v != null) { v.toLong() * 1000L - }else{ - -1L + } else { + - 1L } - location_update_interval_desired = x1000(Pref.uiLocationIntervalDesired.getIntOrNull(pref)) + location_update_interval_desired = + x1000(Pref.uiLocationIntervalDesired.getIntOrNull(pref)) location_update_interval_min = x1000(Pref.uiLocationIntervalMin.getIntOrNull(pref)) - when{ - !repeat ->{} - location_update_interval_desired < 1000L ->{ + when { + ! repeat -> { + } + + location_update_interval_desired < 1000L -> { Utils.showToast(this, true, getString(R.string.location_update_interval_not_ok)) return } - location_update_interval_min < 1000L ->{ + + location_update_interval_min < 1000L -> { Utils.showToast(this, true, getString(R.string.location_update_interval_not_ok)) return } @@ -647,7 +672,7 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { val force_wifi = Pref.uiForceWifi(pref) - val ssid:String + val ssid : String if(! force_wifi) { ssid = "" } else { @@ -663,8 +688,8 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { // 最後に押したボタンを覚えておく pref.edit() - .put( Pref.lastMode,if(repeat) Pref.LAST_MODE_REPEAT else Pref.LAST_MODE_ONCE) - .put( Pref.lastModeUpdate,System.currentTimeMillis()) + .put(Pref.lastMode, if(repeat) Pref.LAST_MODE_REPEAT else Pref.LAST_MODE_ONCE) + .put(Pref.lastModeUpdate, System.currentTimeMillis()) .apply() // 転送サービスを開始 @@ -725,23 +750,18 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { // onCreateから呼ばれる private fun setupIabHelper() { - bRemoveAdPurchased = if(BuildVariant.AD_FREE) { - true - } else { - Pref.purchasedRemoveAd(Pref.pref(this)) - } - - if( bRemoveAdPurchased) return + bRemoveAdPurchased = Pref.purchasedRemoveAd(pref) + if(bRemoveAdPurchased) return try { val iabHelper = IabHelper(this, APP_PUBLIC_KEY) - mIabHelper = iabHelper + mIabHelper = iabHelper iabHelper.startSetup(IabHelper.OnIabSetupFinishedListener { result -> // return if activity is destroyed if(mIabHelper == null) return@OnIabSetupFinishedListener if(! result.isSuccess) { - log.e( "onIabSetupFinished: ${result.response},${result.message}") + log.e("onIabSetupFinished: ${result.response},${result.message}") return@OnIabSetupFinishedListener } @@ -751,7 +771,7 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { mIabHelper?.queryInventoryAsync(mGotInventoryListener) }) } catch(ex : Throwable) { - log.trace(ex,"IabHelper failed.") + log.trace(ex, "IabHelper failed.") // 多分Google Playのない端末 } } @@ -762,7 +782,7 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { val iabHelper = mIabHelper if(iabHelper == null) { Utils.showToast(this, false, getString(R.string.play_store_missing)) - }else{ + } else { iabHelper.launchPurchaseFlow( this, REMOVE_AD_PRODUCT_ID, @@ -775,19 +795,17 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { } } catch(ex : Throwable) { - log.trace(ex,"startRemoveAdPurchase failed.") + log.trace(ex, "startRemoveAdPurchase failed.") } } internal fun remove_ad(isPurchased : Boolean) { bRemoveAdPurchased = isPurchased - if(isPurchased) { - if(mAdView != null) { - (mAdView !!.parent as ViewGroup).removeView(mAdView) - mAdView !!.destroy() - mAdView = null - } + if(isPurchased && mAdView != null) { + (mAdView?.parent as? ViewGroup)?.removeView(mAdView) + mAdView?.destroy() + mAdView = null } val page = pager_adapter.getPage(page_idx_other) @@ -798,5 +816,5 @@ open class ActMain : AppCompatActivity(), View.OnClickListener { val page = pager_adapter.getPage(page_idx_record) page?.viewer?.reload() } - + } diff --git a/app/src/main/java/jp/juggler/fadownloader/DownloadRecordViewer.kt b/app/src/main/java/jp/juggler/fadownloader/DownloadRecordViewer.kt index 317214f..6570eb4 100644 --- a/app/src/main/java/jp/juggler/fadownloader/DownloadRecordViewer.kt +++ b/app/src/main/java/jp/juggler/fadownloader/DownloadRecordViewer.kt @@ -23,7 +23,6 @@ import android.support.v4.app.LoaderManager import android.support.v4.content.CursorLoader import android.support.v4.content.Loader import android.support.v7.app.AppCompatActivity -import android.text.TextUtils import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -39,10 +38,7 @@ import jp.juggler.fadownloader.util.Utils import jp.juggler.fadownloader.util.getStringOrNull import jp.juggler.fadownloader.util.withCaption import org.apache.commons.io.IOUtils -import java.io.File -import java.io.FileInputStream -import java.io.FileOutputStream -import java.io.InputStream +import java.io.* import java.text.SimpleDateFormat import java.util.* import java.util.regex.Pattern @@ -306,7 +302,7 @@ class DownloadRecordViewer { } sv = exif.getTagStringValue(ExifInterface.TAG_MODEL) - if(! TextUtils.isEmpty(sv)) { + if(sv?.isNotEmpty() == true) { exif_list.add(trimModelName(sv)) } @@ -319,6 +315,10 @@ class DownloadRecordViewer { } } + }catch(ex: IllegalArgumentException){ + log.e(ex,"missing $image_uri") + }catch(ex: FileNotFoundException){ + log.e(ex,"missing $image_uri") } catch(ex : Throwable) { log.trace(ex,"exif check failed.") } @@ -414,7 +414,7 @@ class DownloadRecordViewer { if(exif_list == null || exif_list.isEmpty()) return null val sb = StringBuilder() for(s in exif_list) { - if(TextUtils.isEmpty(s)) continue + if(s.isEmpty()) continue if(sb.isNotEmpty()) sb.append(delimiter) sb.append(s) } @@ -422,7 +422,7 @@ class DownloadRecordViewer { } fun showTimeAndExif() { - if(TextUtils.isEmpty(exif_info)) { + if(exif_info?.isEmpty() != false ) { tvTime.text = time_str } else { tvTime.text = "$time_str\n$exif_info" diff --git a/app/src/main/java/jp/juggler/fadownloader/DownloadService.kt b/app/src/main/java/jp/juggler/fadownloader/DownloadService.kt index 0c21c40..a462432 100644 --- a/app/src/main/java/jp/juggler/fadownloader/DownloadService.kt +++ b/app/src/main/java/jp/juggler/fadownloader/DownloadService.kt @@ -25,7 +25,6 @@ import jp.juggler.fadownloader.util.Utils class DownloadService : Service() { companion object { - internal const val ACTION_BROADCAST_RECEIVED = "broadcast_received" internal const val EXTRA_BROADCAST_INTENT = "broadcast_intent" @@ -187,6 +186,10 @@ class DownloadService : Service() { if(intent != null) { var action = intent.action when(action) { + ACTION_START -> { + worker_tracker.start(intent) + } + ACTION_BROADCAST_RECEIVED -> { val broadcast_intent = intent.getParcelableExtra(EXTRA_BROADCAST_INTENT) if(broadcast_intent != null) { @@ -200,10 +203,6 @@ class DownloadService : Service() { } } - ACTION_START -> { - worker_tracker.start(intent) - } - else -> log.d(getString(R.string.unsupported_intent_received, action)) } } @@ -256,16 +255,18 @@ class DownloadService : Service() { fun onThreadStart() { if(! is_alive) return + setServiceNotification(getString(R.string.thread_running)) } internal fun onThreadEnd(complete_and_no_repeat : Boolean) { - if(! is_alive) return + if(! is_alive ) return if(complete_and_no_repeat) { this@DownloadService.cancel_alarm_on_destroy = true stopSelf() } else { + location_tracker.tracking_end() setServiceNotification(getString(R.string.service_idle)) } } @@ -289,7 +290,7 @@ class DownloadService : Service() { "ServiceRunning", "FA Downloader service", "this notification is shown while FA Downloader service is active.", - NotificationManager.IMPORTANCE_DEFAULT, + NotificationManager.IMPORTANCE_LOW, log ) NotificationCompat.Builder(this, channel.id) diff --git a/app/src/main/java/jp/juggler/fadownloader/DownloadWorker.kt b/app/src/main/java/jp/juggler/fadownloader/DownloadWorker.kt index 358d713..14df2b7 100644 --- a/app/src/main/java/jp/juggler/fadownloader/DownloadWorker.kt +++ b/app/src/main/java/jp/juggler/fadownloader/DownloadWorker.kt @@ -9,7 +9,6 @@ import android.net.ConnectivityManager import android.net.wifi.WifiManager import android.os.Build import android.os.SystemClock -import android.text.TextUtils import org.apache.commons.io.IOUtils @@ -41,8 +40,28 @@ class DownloadWorker : WorkerBase { internal const val MACRO_WAIT_UNTIL = "%WAIT_UNTIL%" } - private val service : DownloadService + interface Callback { + + val location : Location? + + fun releaseWakeLock() + + fun acquireWakeLock() + + fun onThreadStart() + + fun onThreadEnd(worker:DownloadWorker,complete_and_no_repeat : Boolean) + + fun onAllFileCompleted(count : Long) + + fun hasHiddenDownloadCount() : Boolean + } + val callback : Callback + + internal var disposed = false + + private val service : DownloadService val repeat : Boolean var target_url : String = "" @@ -140,22 +159,7 @@ class DownloadWorker : WorkerBase { } } - interface Callback { - - val location : Location? - - fun releaseWakeLock() - - fun acquireWakeLock() - - fun onThreadStart() - - fun onThreadEnd(complete_and_no_repeat : Boolean) - - fun onAllFileCompleted(count : Long) - - fun hasHiddenDownloadCount() : Boolean - } + constructor(service : DownloadService, intent : Intent, callback : Callback) { this.service = service @@ -456,21 +460,21 @@ class DownloadWorker : WorkerBase { fun checkSkip(local_file : LocalFile, log : LogWriter, size : Long) : Boolean { // ローカルにあるファイルのサイズが指定以上ならスキップする - if(local_file.length(log) >= size) return true + val localLength = local_file.length(log) + if( localLength >= size){ + return true + } if(skip_already_download) { val name = local_file.name - if(! TextUtils.isEmpty(name)) { + if( name?.isNotEmpty()==true) { service.contentResolver.query( DownloadRecord.meta.content_uri, null, DownloadRecord.COL_NAME + "=?", arrayOf(name), null )?.use { cursor -> - if(cursor.moveToFirst()) { - // ダウンロード履歴に同じ名前のファイルがあるのでスキップする - log.i("skip %s : already found in download record.", name) - return true - } + // ダウンロード履歴に同じ名前のファイルがあるのでスキップする + if(cursor.moveToFirst()) return true } } } @@ -608,10 +612,10 @@ class DownloadWorker : WorkerBase { } fun checkHostError() { - if(client.last_error !!.contains("UnknownHostException")) { + if(client.last_error ?.contains("UnknownHostException") == true) { client.last_error = service.getString(R.string.target_host_error) cancel(service.getString(R.string.target_host_error_short)) - } else if(client.last_error !!.contains("ENETUNREACH")) { + } else if(client.last_error ?.contains("ENETUNREACH") == true ) { client.last_error = service.getString(R.string.target_unreachable) cancel(service.getString(R.string.target_unreachable)) } @@ -654,6 +658,23 @@ class DownloadWorker : WorkerBase { log.trace(ex,"alarm cancel failed") } + // 位置情報を得られるまで待機 + run{ + val timeEnd = SystemClock.elapsedRealtime() + 5000L + while( !isCancelled + && service.location_tracker.isUpdateRequired + && service.location_tracker.location == null + ){ + val remain =timeEnd -SystemClock.elapsedRealtime() + if(remain<=0L){ + log.w( R.string.location_wait_timeout) + break + } + Thread.sleep(1000L) + } + } + + when(target_type) { Pref.TARGET_TYPE_FLASHAIR_AP, Pref.TARGET_TYPE_FLASHAIR_STA -> FlashAir( service, @@ -677,7 +698,7 @@ class DownloadWorker : WorkerBase { } setStatus(false, service.getString(R.string.thread_end)) callback.releaseWakeLock() - callback.onThreadEnd(complete_and_no_repeat) + callback.onThreadEnd(this@DownloadWorker,complete_and_no_repeat) } } diff --git a/app/src/main/java/jp/juggler/fadownloader/NewFileService.kt b/app/src/main/java/jp/juggler/fadownloader/NewFileService.kt index 7af0fb5..6dc5ff8 100644 --- a/app/src/main/java/jp/juggler/fadownloader/NewFileService.kt +++ b/app/src/main/java/jp/juggler/fadownloader/NewFileService.kt @@ -29,21 +29,30 @@ class NewFileService : IntentService("DownloadCountService") { var hidden_count =Pref.downloadCompleteCountHidden(pref) if(hidden_count < 0L) hidden_count = 0L - if(delta > 0L) { - hidden_count += delta - pref.edit().put(Pref.downloadCompleteCountHidden, hidden_count).apply() - return - } else if(hidden_count > 0) { - var count = Pref.downloadCompleteCount(pref) - if(count < 0L) count = 0L - count += hidden_count - hidden_count = 0L - pref.edit() - .put(Pref.downloadCompleteCountHidden, hidden_count) - .put(Pref.downloadCompleteCount, count) - .apply() - - showCount(context, count,log) + when { + // ダウンロードしたファイルが増えた際に呼ばれる + delta > 0L -> { + hidden_count += delta + pref.edit().put(Pref.downloadCompleteCountHidden, hidden_count).apply() + return + } + // スキャン完了時にdelta==0で呼ばれる + // 通知を更新する + hidden_count > 0 -> { + // 表示中のカウント値 + var count = Pref.downloadCompleteCount(pref) + if(count < 0L) count = 0L + // 増えた分を追加する + count += hidden_count + hidden_count = 0L + // 値を保存する + pref.edit() + .put(Pref.downloadCompleteCountHidden, hidden_count) + .put(Pref.downloadCompleteCount, count) + .apply() + // 通知を表示する + showCount(context, count,log) + } } } @@ -107,15 +116,21 @@ class NewFileService : IntentService("DownloadCountService") { } } + // 通知をタップ/消去した時に呼ばれる override fun onHandleIntent(intentArg : Intent?) { + // 通知タップならアプリの画面を開く if(ACTION_TAP == intentArg?.action) { val intent = Intent(this, ActMain::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) intent.putExtra(ActMain.EXTRA_TAB, ActMain.TAB_RECORD) startActivity(intent) } + // 通知を消去する NotificationManagerCompat.from(this).cancel(NOTIFICATION_ID_DOWNLOAD_COMPLETE) + // カウント表示した分をクリアする Pref.pref(this).edit().put(Pref.downloadCompleteCount, 0).apply() + + // ウィジェットがあればカウントを更新する NewFileWidget.update(this) } diff --git a/app/src/main/java/jp/juggler/fadownloader/PageOther.kt b/app/src/main/java/jp/juggler/fadownloader/PageOther.kt index 0aa2e72..2c13231 100644 --- a/app/src/main/java/jp/juggler/fadownloader/PageOther.kt +++ b/app/src/main/java/jp/juggler/fadownloader/PageOther.kt @@ -83,7 +83,6 @@ class PageOther(activity : Activity, ignored : View) : fun updatePurchaseButton() { val act = activity as ActMain - btnRemoveAd.visibility = - if(act.bSetupCompleted && ! act.bRemoveAdPurchased) View.VISIBLE else View.GONE + btnRemoveAd.visibility = if(act.bSetupCompleted && ! act.bRemoveAdPurchased) View.VISIBLE else View.GONE } } diff --git a/app/src/main/java/jp/juggler/fadownloader/model/LocalFile.kt b/app/src/main/java/jp/juggler/fadownloader/model/LocalFile.kt index 6d4834c..c8a1460 100644 --- a/app/src/main/java/jp/juggler/fadownloader/model/LocalFile.kt +++ b/app/src/main/java/jp/juggler/fadownloader/model/LocalFile.kt @@ -4,9 +4,7 @@ import android.content.Context import android.net.Uri import android.os.Build import android.support.v4.provider.DocumentFile -import android.text.TextUtils import jp.juggler.fadownloader.R -import jp.juggler.fadownloader.util.LogTag import jp.juggler.fadownloader.util.LogWriter import jp.juggler.fadownloader.util.Utils import java.io.* @@ -92,7 +90,7 @@ class LocalFile( } child_list = result } catch(ex : Throwable) { - log.trace(ex,"listFiles() failed.") + log.trace(ex, "listFiles() failed.") log.e(ex, "listFiles() failed.") } @@ -130,18 +128,24 @@ class LocalFile( } fun prepareFile(log : LogWriter, bCreate : Boolean, mimeTypeArg : String?) : Boolean { - var mime_type = mimeTypeArg try { if(local_file == null && parent != null && name != null) { if(parent.prepareDirectory(log, bCreate)) { local_file = parent.findChild(log, bCreate, name) if(local_file == null && bCreate) { - if(Build.VERSION.SDK_INT >= DOCUMENT_FILE_VERSION) { - if(TextUtils.isEmpty(mime_type)) mime_type = "application/octet-stream" - local_file = - (parent.local_file as DocumentFile).createFile(mime_type, name) - } else { - local_file = File(parent.local_file as File?, name) + local_file = when { + Build.VERSION.SDK_INT >= DOCUMENT_FILE_VERSION -> + (parent.local_file as DocumentFile) + .createFile( + if(mimeTypeArg?.isNotEmpty() == true) { + mimeTypeArg + } else { + "application/octet-stream" + } + ,name + ) + else -> + File(parent.local_file as File?, name) } if(local_file == null) { log.e(R.string.file_create_failed) @@ -244,8 +248,8 @@ class LocalFile( path.setLastModified(time) } catch(ex : Throwable) { - log.trace(ex,"setLastModified() failed.") - log.e(ex,"setLastModified() failed.") + log.trace(ex, "setLastModified() failed.") + log.e(ex, "setLastModified() failed.") } } diff --git a/app/src/main/java/jp/juggler/fadownloader/picker/FolderPicker.kt b/app/src/main/java/jp/juggler/fadownloader/picker/FolderPicker.kt index 990a6d1..5659dad 100644 --- a/app/src/main/java/jp/juggler/fadownloader/picker/FolderPicker.kt +++ b/app/src/main/java/jp/juggler/fadownloader/picker/FolderPicker.kt @@ -8,7 +8,6 @@ import android.os.AsyncTask import android.os.Bundle import android.os.Environment import android.support.v7.app.AppCompatActivity -import android.text.TextUtils import android.view.View import android.view.WindowManager import android.view.inputmethod.EditorInfo @@ -211,7 +210,7 @@ class FolderPicker : AppCompatActivity(), View.OnClickListener, AdapterView.OnIt btnOk.setOnClickListener {_-> try { val name = etName.text.toString().trim { it <= ' ' } - if(TextUtils.isEmpty(name)) { + if(name.isEmpty()) { Utils.showToast(this@FolderPicker, false, R.string.folder_name_empty ) diff --git a/app/src/main/java/jp/juggler/fadownloader/picker/SSIDPicker.kt b/app/src/main/java/jp/juggler/fadownloader/picker/SSIDPicker.kt index b2cd494..d6e71bd 100644 --- a/app/src/main/java/jp/juggler/fadownloader/picker/SSIDPicker.kt +++ b/app/src/main/java/jp/juggler/fadownloader/picker/SSIDPicker.kt @@ -9,7 +9,6 @@ import android.net.ConnectivityManager import android.net.wifi.WifiManager import android.os.Bundle import android.support.v7.app.AppCompatActivity -import android.text.TextUtils import android.view.View import android.widget.AdapterView import android.widget.ArrayAdapter @@ -31,7 +30,7 @@ class SSIDPicker : AppCompatActivity(), AdapterView.OnItemClickListener, View.On val intent = Intent(activity, SSIDPicker::class.java) activity.startActivityForResult(intent, request_code) } catch(ex : Throwable) { - log.trace(ex,"open failed.") + log.trace(ex, "open failed.") } } @@ -100,7 +99,7 @@ class SSIDPicker : AppCompatActivity(), AdapterView.OnItemClickListener, View.On try { for(wc in wifi_manager.configuredNetworks) { val ssid = wc.SSID.replace("\"", "") - if(! TextUtils.isEmpty(ssid)) set.add(ssid) + if(ssid.isNotEmpty()) set.add(ssid) } } catch(ignored : Throwable) { } @@ -108,7 +107,7 @@ class SSIDPicker : AppCompatActivity(), AdapterView.OnItemClickListener, View.On try { for(result in wifi_manager.scanResults) { val ssid = result.SSID.replace("\"", "") - if(! TextUtils.isEmpty(ssid)) set.add(ssid) + if(ssid.isNotEmpty()) set.add(ssid) } } catch(ignored : Throwable) { } diff --git a/app/src/main/java/jp/juggler/fadownloader/targets/FlashAir.kt b/app/src/main/java/jp/juggler/fadownloader/targets/FlashAir.kt index ef7b858..6f8da4f 100644 --- a/app/src/main/java/jp/juggler/fadownloader/targets/FlashAir.kt +++ b/app/src/main/java/jp/juggler/fadownloader/targets/FlashAir.kt @@ -6,6 +6,7 @@ import jp.juggler.fadownloader.* import jp.juggler.fadownloader.model.LocalFile import jp.juggler.fadownloader.model.ScanItem import jp.juggler.fadownloader.table.DownloadRecord +import jp.juggler.fadownloader.util.LogTag import jp.juggler.fadownloader.util.Utils import jp.juggler.fadownloader.util.decodeUTF8 import java.io.File @@ -15,7 +16,7 @@ import java.util.regex.Pattern class FlashAir(private val service : DownloadService, internal val thread : DownloadWorker) { companion object { - + private val logStatic = LogTag("FlashAir") internal val reLine = Pattern.compile("([^\\x0d\\x0a]+)") internal val reAttr = Pattern.compile(",(\\d+),(\\d+),(\\d+),(\\d+)$") @@ -47,9 +48,9 @@ class FlashAir(private val service : DownloadService, internal val thread : Down } + // フォルダを読む private fun loadFolder(network : Any?, item : ScanItem) { - - // フォルダを読む + val cgi_url = "${thread.target_url}command.cgi?op=100&DIR=${Uri.encode(item.remote_path)}" val data = thread.client.getHTTP(log, network, cgi_url) if(thread.isCancelled) return @@ -103,7 +104,7 @@ class FlashAir(private val service : DownloadService, internal val thread : Down // https://flashair-developers.com/ja/support/forum/#/discussion/3/%E3%82%AB%E3%83%B3%E3%83%9E%E5%8C%BA%E5%88%87%E3%82%8A val dir = if(item.remote_path == "/") "" else item.remote_path val file_name = line.substring(dir.length + 1, mAttr.start()) - + if(attr and 2 != 0) { // skip hidden file continue @@ -117,7 +118,7 @@ class FlashAir(private val service : DownloadService, internal val thread : Down if(attr and 0x10 != 0) { // フォルダはキューの頭に追加 - thread.job_queue?.addFolder( + thread.job_queue!!.addFolder( ScanItem( file_name, remote_path, @@ -134,30 +135,38 @@ class FlashAir(private val service : DownloadService, internal val thread : Down } } + var matched = false for(re in thread.file_type_list) { - if(! re.matcher(file_name).find()) continue - // マッチした - - // ローカルのファイルサイズを調べて既読スキップ - if(thread.checkSkip(local_file, log, size)) continue - - val mime_type = Utils.getMimeType(log, file_name) + if(re.matcher(file_name).find()){ + matched = true + break + } + } + if(!matched) { + logStatic.d("$file_name not match in file_type_list") + continue + } + // ローカルのファイルサイズを調べて既読スキップ + if(thread.checkSkip(local_file, log, size)) { + logStatic.d("$file_name already downloaded.") + continue + } - // ファイルはキューの末尾に追加 - val sub_item = - ScanItem( - file_name, - remote_path, - local_file, - size, - time = time, - mime_type = mime_type - ) - thread.job_queue !!.addFile(sub_item) - thread.record(sub_item, 0L, DownloadRecord.STATE_QUEUED, "queued.") + val mime_type = Utils.getMimeType(log, file_name) + + // ファイルはキューの末尾に追加 + val sub_item = + ScanItem( + file_name, + remote_path, + local_file, + size, + time = time, + mime_type = mime_type + ) + thread.job_queue!!.addFile(sub_item) + thread.record(sub_item, 0L, DownloadRecord.STATE_QUEUED, "queued.") - break - } } } catch(ex : Throwable) { log.trace(ex, "folder list parse error: $line" ) diff --git a/app/src/main/java/jp/juggler/fadownloader/targets/PentaxKP.kt b/app/src/main/java/jp/juggler/fadownloader/targets/PentaxKP.kt index 972f21a..16109a6 100644 --- a/app/src/main/java/jp/juggler/fadownloader/targets/PentaxKP.kt +++ b/app/src/main/java/jp/juggler/fadownloader/targets/PentaxKP.kt @@ -2,7 +2,6 @@ package jp.juggler.fadownloader.targets import android.net.Uri import android.os.SystemClock -import android.text.TextUtils import com.neovisionaries.ws.client.OpeningHandshakeException import com.neovisionaries.ws.client.WebSocket @@ -171,7 +170,7 @@ class PentaxKP(private val service : DownloadService, internal val thread : Down } val sub_dir_name = o.optString("name", null) - if(TextUtils.isEmpty(sub_dir_name)) { + if(sub_dir_name?.isEmpty()!=false) { ++ i continue } @@ -189,7 +188,7 @@ class PentaxKP(private val service : DownloadService, internal val thread : Down while(j < je) { if(thread.isCancelled) return false val file_name = files.optString(j) - if(TextUtils.isEmpty(file_name)) { + if(file_name?.isEmpty()!=false) { ++ j continue } @@ -227,7 +226,7 @@ class PentaxKP(private val service : DownloadService, internal val thread : Down } else { //// thread.client.dump_res_header( log ); val sv = thread.client.getHeaderString("Content-Length", null) - if(! TextUtils.isEmpty(sv)) { + if(sv?.isNotEmpty()==true) { size = java.lang.Long.parseLong(sv, 10) } } @@ -430,7 +429,7 @@ class PentaxKP(private val service : DownloadService, internal val thread : Down log.e(ex, "WebSocket connection failed(2).") val active_other = service.wifi_tracker.otherActive - if(! TextUtils.isEmpty(active_other)) { + if( active_other?.isNotEmpty() ==true ) { log.w(R.string.other_active_warning, active_other) } diff --git a/app/src/main/java/jp/juggler/fadownloader/targets/PqiAirCard.kt b/app/src/main/java/jp/juggler/fadownloader/targets/PqiAirCard.kt index 74a4fc0..ef0eec2 100644 --- a/app/src/main/java/jp/juggler/fadownloader/targets/PqiAirCard.kt +++ b/app/src/main/java/jp/juggler/fadownloader/targets/PqiAirCard.kt @@ -2,7 +2,6 @@ package jp.juggler.fadownloader.targets import android.net.Uri import android.os.SystemClock -import android.text.TextUtils import jp.juggler.fadownloader.* import jp.juggler.fadownloader.model.LocalFile import jp.juggler.fadownloader.model.ScanItem @@ -102,15 +101,15 @@ class PqiAirCard( ++ i continue } - if(TextUtils.isEmpty(size_str)) { + if(size_str?.isEmpty()!=false) { ++ i continue } - if(TextUtils.isEmpty(date_str)) { + if(date_str?.isEmpty()!=false) { ++ i continue } - if(TextUtils.isEmpty(type_str)) { + if(type_str?.isEmpty()!=false) { ++ i continue } diff --git a/app/src/main/java/jp/juggler/fadownloader/tracker/LocationTracker.kt b/app/src/main/java/jp/juggler/fadownloader/tracker/LocationTracker.kt index 9ca85e4..f30367e 100644 --- a/app/src/main/java/jp/juggler/fadownloader/tracker/LocationTracker.kt +++ b/app/src/main/java/jp/juggler/fadownloader/tracker/LocationTracker.kt @@ -2,6 +2,7 @@ package jp.juggler.fadownloader.tracker import android.content.Context import android.location.Location +import android.os.SystemClock import com.google.android.gms.location.* import jp.juggler.fadownloader.R import jp.juggler.fadownloader.util.LogWriter @@ -92,9 +93,13 @@ class LocationTracker( return location_setting?.getModeString(context) ?: "(no location setting)" } + val isUpdateRequired : Boolean + get() = location_setting?.isUpdateRequired == true + + val location : Location? @Synchronized get() = - if(location_setting?.isUpdateRequired != true) { + if(!isUpdateRequired) { null } else { mCurrentLocation @@ -114,12 +119,13 @@ class LocationTracker( tracking_start() } - private fun tracking_end() { + @Synchronized + fun tracking_end() { if(! isTracked) return try { fusedLocationClient.removeLocationUpdates(this) - log.d(R.string.location_update_end) + log.v(R.string.location_update_end) } catch(ex : Throwable) { log.trace(ex,"removeLocationUpdates() failed.") log.e(ex, "removeLocationUpdates() failed.") @@ -175,7 +181,7 @@ class LocationTracker( log.e(ex, R.string.location_update_request_result) } - if(! isTracked) log.d(R.string.location_update_start) + if(! isTracked) log.v(R.string.location_update_start) isTracked = true } catch(ex : SecurityException) { @@ -209,4 +215,6 @@ class LocationTracker( callback(lastLocation) } } + + } diff --git a/app/src/main/java/jp/juggler/fadownloader/tracker/MediaScannerTracker.kt b/app/src/main/java/jp/juggler/fadownloader/tracker/MediaScannerTracker.kt index cd978ca..1a2e36e 100644 --- a/app/src/main/java/jp/juggler/fadownloader/tracker/MediaScannerTracker.kt +++ b/app/src/main/java/jp/juggler/fadownloader/tracker/MediaScannerTracker.kt @@ -5,7 +5,6 @@ import android.media.MediaScannerConnection import android.net.Uri import android.os.Handler import android.os.SystemClock -import android.text.TextUtils import jp.juggler.fadownloader.util.LogWriter import java.io.File @@ -71,16 +70,22 @@ class MediaScannerTracker( internal fun dispose() { is_dispose = true + try{ + conn.disconnect() + }catch(ex:Throwable){ + log.trace(ex,"disconnect failed.") + } } fun addFile(file : File?, mime_type : String) { if(file == null || ! file.isFile) return - if(TextUtils.isEmpty(mime_type)) return - val item = Item() - item.path = file.absolutePath - item.mime_type = mime_type - queue.add(item) - handler.post(queue_reader) + if(mime_type.isNotEmpty() ){ + val item = Item() + item.path = file.absolutePath + item.mime_type = mime_type + queue.add(item) + handler.post(queue_reader) + } } private fun prepareConnection() : Boolean { diff --git a/app/src/main/java/jp/juggler/fadownloader/tracker/NetworkTracker.kt b/app/src/main/java/jp/juggler/fadownloader/tracker/NetworkTracker.kt index 1d245b7..c315e0e 100644 --- a/app/src/main/java/jp/juggler/fadownloader/tracker/NetworkTracker.kt +++ b/app/src/main/java/jp/juggler/fadownloader/tracker/NetworkTracker.kt @@ -12,7 +12,6 @@ import android.net.wifi.WifiInfo import android.net.wifi.WifiManager import android.os.Build import android.os.SystemClock -import android.text.TextUtils import jp.juggler.fadownloader.Pref import jp.juggler.fadownloader.R import jp.juggler.fadownloader.util.* @@ -36,7 +35,7 @@ class NetworkTracker( private val logStatic = LogTag("NetworkTracker") - const val WIFI_SCAN_INTERVAL = 100000 + const val WIFI_SCAN_INTERVAL = 10000 //////////////////////////////////////////////////////////////////////// @@ -66,8 +65,9 @@ class NetworkTracker( sb.append("Wi-Fi(").append(ns.strWifiStatus).append(')') } else { sb.append(ns.type_name) - if(! TextUtils.isEmpty(ns.sub_name)) { - sb.append('(').append(ns.sub_name).append(')') + val sub_name = ns.sub_name + if(sub_name?.isNotEmpty() == true) { + sb.append('(').append(sub_name).append(')') } } } @@ -117,7 +117,7 @@ class NetworkTracker( internal val last_other_active = AtomicReference() - val otherActive : String + val otherActive : String? get() = last_other_active.get() internal val urlChecker_FlashAir : UrlChecker = object : @@ -543,9 +543,15 @@ class NetworkTracker( } // スキャン範囲内に目的のSSIDがあるか? + var lastSeen :Long? = null var found_in_scan = false try { for(result in wifiManager.scanResults) { + if( Build.VERSION.SDK_INT >= 17) { + if(lastSeen == null || result.timestamp > lastSeen){ + lastSeen = result.timestamp + } + } if(target_ssid != null && target_ssid == result.SSID.replace("\"", "")) { found_in_scan = true break @@ -559,13 +565,14 @@ class NetworkTracker( // スキャン範囲内にない場合、定期的にスキャン開始 if(! found_in_scan) { - force_status = - context.getString(R.string.wifi_target_ssid_not_scanned, target_ssid) - - // 定期的にスキャン開始 try { + force_status = context.getString(R.string.wifi_target_ssid_not_scanned, target_ssid) val now = SystemClock.elapsedRealtime() - if(now - last_wifi_scan_start >= WIFI_SCAN_INTERVAL) { + val remain = last_wifi_scan_start + WIFI_SCAN_INTERVAL - now + if( remain > 0L){ + val lastSeenBefore = if(lastSeen==null) null else now - (lastSeen/1000L) + logStatic.d("$target_ssid is not found in latest scan result(${lastSeenBefore}ms before). next scan is start after ${remain}ms.") + }else{ last_wifi_scan_start = now wifiManager.startScan() log.d(R.string.wifi_scan_start) @@ -574,12 +581,14 @@ class NetworkTracker( log.trace(ex,"startScan() failed.") error_status = ex.withCaption( "startScan() failed.") } - return false } val now = SystemClock.elapsedRealtime() - if(now - last_wifi_ap_change >= 5000L) { + val remain = last_wifi_ap_change + 5000L - now + if( remain > 0L){ + logStatic.d("wait ${remain}ms before force change WiFi AP") + }else{ last_wifi_ap_change = now try { @@ -588,17 +597,17 @@ class NetworkTracker( if(wc.networkId != target_config.networkId) { val ssid = wc.SSID.replace("\"", "") if(wc.status == WifiConfiguration.Status.CURRENT) { - log.d("%sから切断させます", ssid) + log.i("%sから切断させます", ssid) wifiManager.disableNetwork(wc.networkId) } else if(wc.status == WifiConfiguration.Status.ENABLED) { - log.d("%sへの自動接続を無効化します", ssid) + log.i("%sへの自動接続を無効化します", ssid) wifiManager.disableNetwork(wc.networkId) } } } val target_ssid = target_config.SSID.replace("\"", "") - log.d("%s への接続を試みます", target_ssid) + log.i("%s への接続を試みます", target_ssid) wifiManager.enableNetwork(target_config.networkId, true) return false @@ -671,6 +680,7 @@ class NetworkTracker( result = keep_ap() if(isCancelled) break } catch(ex : Throwable) { + log.trace(ex,"network check failed.") log.e(ex, "network check failed.") result = false } @@ -681,11 +691,12 @@ class NetworkTracker( try { if(!is_dispose) callback(true, "Wi-Fi tracker") } catch(ex : Throwable) { + log.trace(ex,"connection event handling failed.") log.e(ex, "connection event handling failed.") } } } - val next = if(result) 30000L else 3000L + val next = if(result) 5000L else 1000L waitEx(next) } } diff --git a/app/src/main/java/jp/juggler/fadownloader/tracker/WorkerTracker.kt b/app/src/main/java/jp/juggler/fadownloader/tracker/WorkerTracker.kt index ac03c32..8084bd2 100644 --- a/app/src/main/java/jp/juggler/fadownloader/tracker/WorkerTracker.kt +++ b/app/src/main/java/jp/juggler/fadownloader/tracker/WorkerTracker.kt @@ -23,8 +23,7 @@ class WorkerTracker( internal var tracker_dispose_complete : Boolean = false internal var worker : DownloadWorker? = null - internal var worker_disposed : Boolean = false - + // パラメータ指定付きでのスレッド作成フラグ internal var will_restart : Boolean = false internal var start_param : Intent? = null @@ -33,12 +32,48 @@ class WorkerTracker( internal var will_wakeup : Boolean = false internal var wakeup_cause : String? = null - internal val proc_check : Runnable = object : Runnable { + private val worker_callback : DownloadWorker.Callback = object : + DownloadWorker.Callback { + + override val location : Location? + get() = if(tracker_disposed) null else service.location_tracker.location + + override fun onThreadEnd(worker:DownloadWorker,complete_and_no_repeat : Boolean) { + Utils.runOnMainThread { + worker.disposed = true + service.onThreadEnd(complete_and_no_repeat) + proc_check.run() + } + } + + override fun onThreadStart() { + service.onThreadStart() + } + + override fun releaseWakeLock() { + if(will_restart || will_wakeup) return + service.releaseWakeLock() + } + + override fun acquireWakeLock() { + service.acquireWakeLock() + } + + override fun onAllFileCompleted(count : Long) { + service.addHiddenDownloadCount(count,log) + } + + override fun hasHiddenDownloadCount() : Boolean { + return service.hasHiddenDownloadCount() + } + } + + private val proc_check : Runnable = object : Runnable { override fun run() { handler.removeCallbacks(this) if(tracker_disposed) { - if(! worker_disposed) { + if(worker?.disposed == false ) { worker?.cancel(service.getString(R.string.service_end)) handler.postDelayed(this, 3000L) } else { @@ -49,7 +84,7 @@ class WorkerTracker( val start_param = this@WorkerTracker.start_param if(will_restart && start_param != null) { - if(! worker_disposed) { + if(worker?.disposed == false ) { worker?.cancel(service.getString(R.string.manual_restart)) handler.postDelayed(this, 3000L) return @@ -62,13 +97,13 @@ class WorkerTracker( try { will_restart = false - worker_disposed = false - worker = DownloadWorker( + val worker =DownloadWorker( service, start_param, worker_callback ) - worker !!.start() + this@WorkerTracker.worker = worker + worker.start() } catch(ex : Throwable) { log.trace(ex,"thread start failed.") log.e(ex, "thread start failed.") @@ -89,7 +124,7 @@ class WorkerTracker( return } - ! worker_disposed -> { + ! worker.disposed -> { // dispose 完了を待つ log.d("waiting dispose previous thread..") handler.postDelayed(this, 3000L) @@ -100,9 +135,7 @@ class WorkerTracker( try { will_wakeup = false - worker_disposed = false - worker = - DownloadWorker( + worker = DownloadWorker( service, wakeup_cause ?: "will_wakeup", worker_callback @@ -118,41 +151,6 @@ class WorkerTracker( } } - internal val worker_callback : DownloadWorker.Callback = object : - DownloadWorker.Callback { - - override val location : Location? - get() = if(tracker_disposed) null else service.location_tracker.location - - override fun onThreadEnd(complete_and_no_repeat : Boolean) { - Utils.runOnMainThread { - worker_disposed = true - service.onThreadEnd(complete_and_no_repeat) - proc_check.run() - } - } - - override fun onThreadStart() { - service.onThreadStart() - } - - override fun releaseWakeLock() { - if(will_restart || will_wakeup) return - service.releaseWakeLock() - } - - override fun acquireWakeLock() { - service.acquireWakeLock() - } - - override fun onAllFileCompleted(count : Long) { - service.addHiddenDownloadCount(count,log) - } - - override fun hasHiddenDownloadCount() : Boolean { - return service.hasHiddenDownloadCount() - } - } // サービス終了時に破棄される fun dispose() { diff --git a/app/src/main/java/jp/juggler/fadownloader/util/NotificationHelper.kt b/app/src/main/java/jp/juggler/fadownloader/util/NotificationHelper.kt index 73d8f5e..819c754 100644 --- a/app/src/main/java/jp/juggler/fadownloader/util/NotificationHelper.kt +++ b/app/src/main/java/jp/juggler/fadownloader/util/NotificationHelper.kt @@ -31,8 +31,8 @@ object NotificationHelper { channel = NotificationChannel(channel_id, name, importance) } channel.name = name - channel.importance = importance if(description != null) channel.description = description + // 上書きしない channel.importance = importance notification_manager.createNotificationChannel(channel) return channel diff --git a/app/src/main/java/jp/juggler/fadownloader/util/Utils.kt b/app/src/main/java/jp/juggler/fadownloader/util/Utils.kt index f6fd8c5..5e63355 100644 --- a/app/src/main/java/jp/juggler/fadownloader/util/Utils.kt +++ b/app/src/main/java/jp/juggler/fadownloader/util/Utils.kt @@ -9,7 +9,6 @@ import android.database.Cursor import android.net.Uri import android.os.* import android.os.storage.StorageManager -import android.text.TextUtils import android.util.Base64 import android.util.SparseBooleanArray import android.util.SparseIntArray @@ -304,23 +303,21 @@ object Utils { fun getMimeType(log : LogWriter?, src : String) : String { var ext = MimeTypeMap.getFileExtensionFromUrl(src) - if(! TextUtils.isEmpty(ext)) { + if( ext?.isNotEmpty() == true) { ext = ext.toLowerCase(Locale.US) // var mime_type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext) - if(! TextUtils.isEmpty(mime_type)) return mime_type + if(mime_type?.isNotEmpty() == true) return mime_type // mime_type = findMimeTypeEx(ext) - if(! TextUtils.isEmpty(mime_type)) return mime_type + if(mime_type?.isNotEmpty() == true) return mime_type // 戻り値が空文字列の場合とnullの場合があり、空文字列の場合は既知でありログ出力しない - - if(mime_type == null && log != null) log.w( - "getMimeType(): unknown file extension '%s'", - ext - ) + if(mime_type == null){ + log?.w("getMimeType(): unknown file extension '$ext'") + } } return MIME_TYPE_APPLICATION_OCTET_STREAM } @@ -391,9 +388,10 @@ object Utils { fun toCamelCase(src : String) : String { val sb = StringBuilder() for(s in src.split("_".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) { - if(TextUtils.isEmpty(s)) continue - sb.append(Character.toUpperCase(s[0])) - sb.append(s.substring(1, s.length).toLowerCase()) + if(s.isNotEmpty()){ + sb.append(Character.toUpperCase(s[0])) + sb.append(s.substring(1, s.length).toLowerCase()) + } } return sb.toString() } @@ -516,10 +514,8 @@ object Utils { if(type != Cursor.FIELD_TYPE_STRING) continue val name = cursor.getColumnName(i) val value = if(cursor.isNull(i)) null else cursor.getString(i) - if(! TextUtils.isEmpty(value)) { - if("filePath" == name) { - return File(value !!) - } + if( "filePath" == name && value?.isNotEmpty() == true) { + return File(value ) } } } diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 03fbb34..65f92d6 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -161,4 +161,5 @@ ONにすると、プロテクト(リードオンリー属性)のついたファイルだけを転送対象にします。 現時点ではFlashAirのみこの機能に対応しています ダウンロード履歴に名前があるファイルはスキップ ダウンロード履歴に名前があるファイルはダウンロードしません。 + 少し待機しましたが位置情報を取得できません。JPEG画像への位置情報の付与を行えません。 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 08bbddb..de5bb44 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -212,5 +212,6 @@ FADownloaderはテザリング内部のLANにUDPパケットをばらまいた ONにすると、プロテクト(リードオンリー属性)のついたファイルだけを転送対象にします。 現時点ではFlashAirのみこの機能に対応しています Skip file name match in download record skip download if the file name is matches in download record. + Waited for a while, but failed to acquire location information. Can not update location information for JPEG image.