/* * Copyright © 2013 – 2016 Ricki Hirner (bitfire web engineering). * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html */ package com.etesync.syncadapter.ui import android.accounts.Account import android.content.ContentResolver import android.content.Context import android.content.Intent import android.content.SyncStatusObserver import android.os.Bundle import android.provider.CalendarContract import android.text.TextUtils import android.view.MenuItem import androidx.appcompat.app.AlertDialog import androidx.core.app.NavUtils import androidx.core.net.toUri import androidx.fragment.app.Fragment import androidx.loader.app.LoaderManager import androidx.loader.content.AsyncTaskLoader import androidx.loader.content.Loader import androidx.preference.* import at.bitfire.ical4android.TaskProvider.Companion.TASK_PROVIDERS import com.etebase.client.exceptions.EtebaseException import com.etesync.syncadapter.* import com.etesync.syncadapter.Constants.KEY_ACCOUNT import com.etesync.syncadapter.R import com.etesync.syncadapter.log.Logger import com.etesync.syncadapter.ui.setup.LoginCredentials import com.etesync.syncadapter.ui.setup.LoginCredentialsChangeFragment import org.jetbrains.anko.doAsync import org.jetbrains.anko.uiThread class AccountSettingsActivity : BaseActivity() { private lateinit var account: Account override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) account = intent.getParcelableExtra(KEY_ACCOUNT)!! title = getString(R.string.settings_title, account.name) supportActionBar!!.setDisplayHomeAsUpEnabled(true) if (savedInstanceState == null) { val settings = AccountSettings(this, account) val frag: Fragment = if (settings.isLegacy) LegacyAccountSettingsFragment() else AccountSettingsFragment() frag.arguments = intent.extras supportFragmentManager.beginTransaction() .replace(android.R.id.content, frag) .commit() } } override fun onOptionsItemSelected(item: MenuItem): Boolean { if (item.itemId == android.R.id.home) { val intent = Intent(this, AccountActivity::class.java) intent.putExtra(AccountActivity.EXTRA_ACCOUNT, account) NavUtils.navigateUpTo(this, intent) return true } else return false } } class AccountSettingsFragment() : PreferenceFragmentCompat(), LoaderManager.LoaderCallbacks { internal lateinit var account: Account override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) account = arguments?.getParcelable(KEY_ACCOUNT)!! loaderManager.initLoader(0, arguments, this) } override fun onCreatePreferences(bundle: Bundle, s: String) { addPreferencesFromResource(R.xml.settings_account) } override fun onCreateLoader(id: Int, args: Bundle?): Loader { return AccountSettingsLoader(requireContext(), (args!!.getParcelable(KEY_ACCOUNT) as Account?)!!) } override fun onLoadFinished(loader: Loader, settings: AccountSettings?) { if (settings == null) { activity?.finish() return } // Category: dashboard val prefManageAccount = findPreference("manage_account") prefManageAccount.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ -> doAsync { try { val httpClient = HttpClient.Builder(requireContext()).build() val etebase = EtebaseLocalCache.getEtebase(requireContext(), httpClient.okHttpClient, settings) val url = etebase.fetchDashboardUrl() uiThread { WebViewActivity.openUrl(requireActivity(), url.toUri()) } } catch (e: EtebaseException) { uiThread { val context = context if (context != null) { AlertDialog.Builder(context) .setIcon(R.drawable.ic_error_dark) .setTitle(R.string.exception) .setMessage(e.localizedMessage) .setPositiveButton(android.R.string.yes) { _, _ -> } .show() } } } } true } // Category: encryption val prefEncryptionPassword = findPreference("password") prefEncryptionPassword.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ -> startActivity(ChangeEncryptionPasswordActivity.newIntent(activity!!, account)) true } val prefSync = findPreference("sync_interval") as ListPreference val syncInterval = settings.getSyncInterval(CalendarContract.AUTHORITY) // Calendar is the baseline interval if (syncInterval != null) { prefSync.value = syncInterval.toString() if (syncInterval == AccountSettings.SYNC_INTERVAL_MANUALLY) prefSync.setSummary(R.string.settings_sync_summary_manually) else prefSync.summary = getString(R.string.settings_sync_summary_periodically, prefSync.entry) prefSync.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> val newInterval = java.lang.Long.parseLong(newValue as String) settings.setSyncInterval(App.addressBooksAuthority, newInterval) settings.setSyncInterval(CalendarContract.AUTHORITY, newInterval) TASK_PROVIDERS.forEach { settings.setSyncInterval(it.authority, newInterval) } loaderManager.restartLoader(0, arguments, this@AccountSettingsFragment) false } } else { prefSync.isEnabled = false prefSync.setSummary(R.string.settings_sync_summary_not_available) } val prefWifiOnly = findPreference("sync_wifi_only") as SwitchPreferenceCompat prefWifiOnly.isChecked = settings.syncWifiOnly prefWifiOnly.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, wifiOnly -> settings.setSyncWiFiOnly(wifiOnly as Boolean) loaderManager.restartLoader(0, arguments, this@AccountSettingsFragment) false } val prefWifiOnlySSID = findPreference("sync_wifi_only_ssid") as EditTextPreference val onlySSID = settings.syncWifiOnlySSID prefWifiOnlySSID.text = onlySSID if (onlySSID != null) prefWifiOnlySSID.summary = getString(R.string.settings_sync_wifi_only_ssid_on, onlySSID) else prefWifiOnlySSID.setSummary(R.string.settings_sync_wifi_only_ssid_off) prefWifiOnlySSID.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> val ssid = newValue as String settings.syncWifiOnlySSID = if (!TextUtils.isEmpty(ssid)) ssid else null loaderManager.restartLoader(0, arguments, this@AccountSettingsFragment) false } } override fun onLoaderReset(loader: Loader) {} } class LegacyAccountSettingsFragment : PreferenceFragmentCompat(), LoaderManager.LoaderCallbacks { internal lateinit var account: Account override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) account = arguments?.getParcelable(KEY_ACCOUNT)!! loaderManager.initLoader(0, arguments, this) } override fun onCreatePreferences(bundle: Bundle, s: String) { addPreferencesFromResource(R.xml.settings_account_legacy) } override fun onCreateLoader(id: Int, args: Bundle?): Loader { return AccountSettingsLoader(context!!, (args!!.getParcelable(KEY_ACCOUNT) as? Account)!!) } override fun onLoadFinished(loader: Loader, settings: AccountSettings?) { if (settings == null) { activity!!.finish() return } // Category: dashboard val prefManageAccount = findPreference("manage_account") prefManageAccount.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ -> WebViewActivity.openUrl(activity!!, Constants.dashboard.buildUpon().appendQueryParameter("email", account.name).build()) true } // category: authentication val prefPassword = findPreference("password") as EditTextPreference prefPassword.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> val credentials = if (newValue != null) LoginCredentials(settings.uri, account.name, newValue as String) else null LoginCredentialsChangeFragment.newInstance(account, credentials!!).show(fragmentManager!!, null) loaderManager.restartLoader(0, arguments, this@LegacyAccountSettingsFragment) false } // Category: encryption val prefEncryptionPassword = findPreference("encryption_password") prefEncryptionPassword.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ -> startActivity(ChangeEncryptionPasswordActivity.newIntent(activity!!, account)) true } val prefSync = findPreference("sync_interval") as ListPreference val syncInterval = settings.getSyncInterval(CalendarContract.AUTHORITY) // Calendar is the baseline interval if (syncInterval != null) { prefSync.value = syncInterval.toString() if (syncInterval == AccountSettings.SYNC_INTERVAL_MANUALLY) prefSync.setSummary(R.string.settings_sync_summary_manually) else prefSync.summary = getString(R.string.settings_sync_summary_periodically, prefSync.entry) prefSync.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> val newInterval = java.lang.Long.parseLong(newValue as String) settings.setSyncInterval(App.addressBooksAuthority, newInterval) settings.setSyncInterval(CalendarContract.AUTHORITY, newInterval) TASK_PROVIDERS.forEach { settings.setSyncInterval(it.authority, newInterval) } loaderManager.restartLoader(0, arguments, this@LegacyAccountSettingsFragment) false } } else { prefSync.isEnabled = false prefSync.setSummary(R.string.settings_sync_summary_not_available) } val prefWifiOnly = findPreference("sync_wifi_only") as SwitchPreferenceCompat prefWifiOnly.isChecked = settings.syncWifiOnly prefWifiOnly.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, wifiOnly -> settings.setSyncWiFiOnly(wifiOnly as Boolean) loaderManager.restartLoader(0, arguments, this@LegacyAccountSettingsFragment) false } val prefWifiOnlySSID = findPreference("sync_wifi_only_ssid") as EditTextPreference val onlySSID = settings.syncWifiOnlySSID prefWifiOnlySSID.text = onlySSID if (onlySSID != null) prefWifiOnlySSID.summary = getString(R.string.settings_sync_wifi_only_ssid_on, onlySSID) else prefWifiOnlySSID.setSummary(R.string.settings_sync_wifi_only_ssid_off) prefWifiOnlySSID.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> val ssid = newValue as String settings.syncWifiOnlySSID = if (!TextUtils.isEmpty(ssid)) ssid else null loaderManager.restartLoader(0, arguments, this@LegacyAccountSettingsFragment) false } } override fun onLoaderReset(loader: Loader) {} } private class AccountSettingsLoader(context: Context, internal val account: Account) : AsyncTaskLoader(context), SyncStatusObserver { internal lateinit var listenerHandle: Any override fun onStartLoading() { forceLoad() listenerHandle = ContentResolver.addStatusChangeListener(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS, this) } override fun onStopLoading() { ContentResolver.removeStatusChangeListener(listenerHandle) } override fun abandon() { onStopLoading() } override fun loadInBackground(): AccountSettings? { val settings: AccountSettings try { settings = AccountSettings(context, account) } catch (e: InvalidAccountException) { return null } return settings } override fun onStatusChanged(which: Int) { Logger.log.fine("Reloading account settings") forceLoad() } }