Merge branch 'android12' into patch-2
This commit is contained in:
commit
64c8430046
37 changed files with 341 additions and 167 deletions
|
|
@ -50,7 +50,7 @@ open class App : Application() {
|
|||
factory<IBackupManager> { IBackupManager.Stub.asInterface(getService(BACKUP_SERVICE)) }
|
||||
factory { AppListRetriever(this@App, get(), get(), get()) }
|
||||
|
||||
viewModel { SettingsViewModel(this@App, get(), get(), get(), get(), get(), get()) }
|
||||
viewModel { SettingsViewModel(this@App, get(), get(), get(), get(), get(), get(), get()) }
|
||||
viewModel { RecoveryCodeViewModel(this@App, get(), get(), get(), get(), get(), get()) }
|
||||
viewModel { BackupStorageViewModel(this@App, get(), get(), get(), get()) }
|
||||
viewModel { RestoreStorageViewModel(this@App, get(), get()) }
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@ import android.widget.TextView
|
|||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.content.ContextCompat.getColor
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.stevesoltys.seedvault.R
|
||||
import com.stevesoltys.seedvault.ui.AppBackupState.FAILED_NOT_INSTALLED
|
||||
|
|
@ -54,7 +52,6 @@ class RestoreProgressFragment : Fragment() {
|
|||
appList.apply {
|
||||
layoutManager = this@RestoreProgressFragment.layoutManager
|
||||
adapter = this@RestoreProgressFragment.adapter
|
||||
addItemDecoration(DividerItemDecoration(context, VERTICAL))
|
||||
}
|
||||
|
||||
button.setText(R.string.restore_finished_button)
|
||||
|
|
|
|||
|
|
@ -41,7 +41,12 @@ internal class ApkRestore(
|
|||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
fun restore(backup: RestorableBackup) = flow {
|
||||
// filter out packages without APK and get total
|
||||
val packages = backup.packageMetadataMap.filter { it.value.hasApk() }
|
||||
val packages = backup.packageMetadataMap.filter {
|
||||
// We also need to exclude the DocumentsProvider used to retrieve backup data.
|
||||
// Otherwise, it gets killed when we install it, terminating our restoration.
|
||||
val isStorageProvider = it.key == storagePlugin.providerPackageName
|
||||
it.value.hasApk() && !isStorageProvider
|
||||
}
|
||||
val total = packages.size
|
||||
var progress = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.stevesoltys.seedvault.restore.install
|
||||
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
|
|
@ -44,7 +45,8 @@ internal class InstallProgressAdapter(
|
|||
return if (finished) finishedComparator.compare(item1, item2)
|
||||
else item1.compareTo(item2)
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AppInstallViewHolder {
|
||||
val v = LayoutInflater.from(parent.context)
|
||||
|
|
@ -79,15 +81,23 @@ internal class InstallProgressAdapter(
|
|||
IN_PROGRESS -> {
|
||||
appStatus.visibility = INVISIBLE
|
||||
progressBar.visibility = VISIBLE
|
||||
if (SDK_INT >= 30) {
|
||||
progressBar.stateDescription =
|
||||
context.getString(R.string.restore_app_status_installing)
|
||||
}
|
||||
}
|
||||
SUCCEEDED -> {
|
||||
appStatus.setImageResource(R.drawable.ic_check_green)
|
||||
appStatus.visibility = VISIBLE
|
||||
appStatus.contentDescription =
|
||||
context.getString(R.string.restore_app_status_installed)
|
||||
progressBar.visibility = INVISIBLE
|
||||
}
|
||||
FAILED -> {
|
||||
appStatus.setImageResource(R.drawable.ic_error_red)
|
||||
appStatus.visibility = VISIBLE
|
||||
appStatus.contentDescription =
|
||||
context.getString(R.string.restore_app_status_install_error)
|
||||
progressBar.visibility = INVISIBLE
|
||||
if (finished) {
|
||||
v.background = clickableBackground
|
||||
|
|
@ -100,6 +110,8 @@ internal class InstallProgressAdapter(
|
|||
}
|
||||
FAILED_SYSTEM_APP -> {
|
||||
appStatus.setImageResource(R.drawable.ic_error_red)
|
||||
appStatus.contentDescription =
|
||||
context.getString(R.string.restore_app_status_install_error)
|
||||
appStatus.visibility = VISIBLE
|
||||
progressBar.visibility = INVISIBLE
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,7 @@ import android.widget.Toast.LENGTH_LONG
|
|||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager.VERTICAL
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.stevesoltys.seedvault.R
|
||||
import com.stevesoltys.seedvault.restore.RestoreViewModel
|
||||
|
|
@ -58,22 +56,21 @@ class InstallProgressFragment : Fragment(), InstallItemListener {
|
|||
appList.apply {
|
||||
layoutManager = this@InstallProgressFragment.layoutManager
|
||||
adapter = this@InstallProgressFragment.adapter
|
||||
addItemDecoration(DividerItemDecoration(context, VERTICAL))
|
||||
}
|
||||
button.setText(R.string.restore_next)
|
||||
button.setOnClickListener { viewModel.onNextClickedAfterInstallingApps() }
|
||||
|
||||
viewModel.chosenRestorableBackup.observe(viewLifecycleOwner, { restorableBackup ->
|
||||
viewModel.chosenRestorableBackup.observe(viewLifecycleOwner) { restorableBackup ->
|
||||
backupNameView.text = restorableBackup.name
|
||||
})
|
||||
}
|
||||
|
||||
viewModel.installResult.observe(viewLifecycleOwner, { result ->
|
||||
viewModel.installResult.observe(viewLifecycleOwner) { result ->
|
||||
onInstallResult(result)
|
||||
})
|
||||
}
|
||||
|
||||
viewModel.nextButtonEnabled.observe(viewLifecycleOwner, { enabled ->
|
||||
viewModel.nextButtonEnabled.observe(viewLifecycleOwner) { enabled ->
|
||||
button.isEnabled = enabled
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun onInstallResult(installResult: InstallResult) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.stevesoltys.seedvault.settings
|
||||
|
||||
import android.app.Application
|
||||
import android.app.backup.IBackupManager
|
||||
import android.app.job.JobInfo.NETWORK_TYPE_NONE
|
||||
import android.app.job.JobInfo.NETWORK_TYPE_UNMETERED
|
||||
import android.content.Intent
|
||||
|
|
@ -49,6 +50,7 @@ internal class SettingsViewModel(
|
|||
private val metadataManager: MetadataManager,
|
||||
private val appListRetriever: AppListRetriever,
|
||||
private val storageBackup: StorageBackup,
|
||||
private val backupManager: IBackupManager,
|
||||
) : RequireProvisioningViewModel(app, settingsManager, keyManager) {
|
||||
|
||||
private val contentResolver = app.contentResolver
|
||||
|
|
@ -157,6 +159,8 @@ internal class SettingsViewModel(
|
|||
// maybe replace the check below with one that checks if our transport service is running
|
||||
if (notificationManager.hasActiveBackupNotifications()) {
|
||||
Toast.makeText(app, R.string.notification_backup_already_running, LENGTH_LONG).show()
|
||||
} else if (!backupManager.isBackupEnabled) {
|
||||
Toast.makeText(app, R.string.notification_backup_disabled, LENGTH_LONG).show()
|
||||
} else viewModelScope.launch(Dispatchers.IO) {
|
||||
if (settingsManager.isStorageBackupEnabled()) {
|
||||
val i = Intent(app, StorageBackupService::class.java)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.stevesoltys.seedvault.ui
|
|||
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build.VERSION.SDK_INT
|
||||
import android.view.View
|
||||
import android.view.View.GONE
|
||||
import android.view.View.INVISIBLE
|
||||
|
|
@ -39,21 +40,45 @@ internal abstract class AppViewHolder(protected val v: View) : RecyclerView.View
|
|||
appInfo.visibility = GONE
|
||||
appStatus.visibility = INVISIBLE
|
||||
progressBar.visibility = VISIBLE
|
||||
if (SDK_INT >= 30) {
|
||||
progressBar.stateDescription = context.getString(
|
||||
if (isRestore) R.string.restore_restoring
|
||||
else R.string.backup_app_in_progress
|
||||
)
|
||||
}
|
||||
} else {
|
||||
appStatus.visibility = VISIBLE
|
||||
progressBar.visibility = INVISIBLE
|
||||
appInfo.visibility = GONE
|
||||
val contentDescription: String?
|
||||
when (state) {
|
||||
SUCCEEDED -> appStatus.setImageResource(R.drawable.ic_check_green)
|
||||
FAILED -> appStatus.setImageResource(R.drawable.ic_error_red)
|
||||
SUCCEEDED -> {
|
||||
appStatus.setImageResource(R.drawable.ic_check_green)
|
||||
contentDescription = context.getString(
|
||||
if (isRestore) R.string.restore_app_status_restored
|
||||
else R.string.backup_app_success
|
||||
)
|
||||
}
|
||||
FAILED -> {
|
||||
appStatus.setImageResource(R.drawable.ic_error_red)
|
||||
contentDescription = context.getString(
|
||||
if (isRestore) R.string.restore_app_status_failed
|
||||
else R.string.notification_failed_title
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
appStatus.setImageResource(R.drawable.ic_warning_yellow)
|
||||
contentDescription = context.getString(
|
||||
if (isRestore) R.string.restore_app_status_warning
|
||||
else R.string.backup_app_warning
|
||||
)
|
||||
appInfo.text =
|
||||
if (isRestore) state.getRestoreText(context)
|
||||
else state.getBackupText(context)
|
||||
appInfo.visibility = VISIBLE
|
||||
}
|
||||
}
|
||||
appStatus.contentDescription = contentDescription
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@ internal class BackupNotificationManager(private val context: Context) {
|
|||
val notification = Builder(context, CHANNEL_ID_OBSERVER).apply {
|
||||
setSmallIcon(R.drawable.ic_cloud_upload)
|
||||
setContentTitle(context.getString(R.string.notification_title))
|
||||
setOngoing(true)
|
||||
setShowWhen(false)
|
||||
setWhen(System.currentTimeMillis())
|
||||
setProgress(0, 0, true)
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ internal class StorageOptionsFragment : Fragment(), StorageOptionClickedListener
|
|||
private lateinit var titleView: TextView
|
||||
private lateinit var warningIcon: ImageView
|
||||
private lateinit var warningText: TextView
|
||||
private lateinit var divider: View
|
||||
private lateinit var listView: RecyclerView
|
||||
private lateinit var progressBar: ProgressBar
|
||||
private lateinit var skipView: TextView
|
||||
|
|
@ -61,7 +60,6 @@ internal class StorageOptionsFragment : Fragment(), StorageOptionClickedListener
|
|||
titleView = v.findViewById(R.id.titleView)
|
||||
warningIcon = v.findViewById(R.id.warningIcon)
|
||||
warningText = v.findViewById(R.id.warningText)
|
||||
divider = v.findViewById(R.id.divider)
|
||||
listView = v.findViewById(R.id.listView)
|
||||
progressBar = v.findViewById(R.id.progressBar)
|
||||
skipView = v.findViewById(R.id.skipView)
|
||||
|
|
@ -93,7 +91,6 @@ internal class StorageOptionsFragment : Fragment(), StorageOptionClickedListener
|
|||
warningText.setText(R.string.storage_fragment_warning_delete)
|
||||
}
|
||||
warningText.visibility = VISIBLE
|
||||
divider.visibility = VISIBLE
|
||||
}
|
||||
|
||||
listView.adapter = adapter
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/skipView"
|
||||
style="@style/SudSecondaryButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="40dp"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:padding="16dp"
|
||||
android:text="@string/restore_storage_skip"
|
||||
android:textColor="?android:colorAccent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
|
|
|||
|
|
@ -60,29 +60,24 @@
|
|||
|
||||
<Button
|
||||
android:id="@+id/doneButton"
|
||||
style="@style/ActionPrimaryButton"
|
||||
style="@style/SudPrimaryButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:text="@string/recovery_code_done_button"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/newCodeButton"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/newCodeButton"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
style="@style/SudSecondaryButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_marginStart="40dp"
|
||||
android:text="@string/recovery_code_verification_generate_new"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/doneButton"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -71,16 +71,13 @@
|
|||
|
||||
<Button
|
||||
android:id="@+id/confirmCodeButton"
|
||||
style="@style/ActionPrimaryButton"
|
||||
style="@style/SudPrimaryButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/recovery_code_confirm_button"
|
||||
android:layout_marginEnd="40dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/wordList" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
style="@style/SudHeaderIcon"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_cloud_restore"
|
||||
|
|
@ -19,21 +16,19 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/titleView"
|
||||
style="@style/SudHeaderTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/restore_storage_in_progress_title"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageView" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/infoView"
|
||||
style="@style/SudContent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/restore_storage_in_progress_info"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
@ -41,15 +36,13 @@
|
|||
|
||||
<Button
|
||||
android:id="@+id/button"
|
||||
style="@style/Widget.AppCompat.Button.Colored"
|
||||
style="@style/SudPrimaryButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:text="@string/restore_storage_got_it"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/infoView"
|
||||
app:layout_constraintVertical_bias="1.0" />
|
||||
|
||||
|
|
|
|||
|
|
@ -5,61 +5,60 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="4dp"
|
||||
android:indeterminate="false"
|
||||
android:padding="0dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:max="23"
|
||||
tools:progress="5" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
style="@style/SudHeaderIcon"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/progressBar"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_cloud_download"
|
||||
app:tint="?android:colorAccent"
|
||||
tools:ignore="ContentDescription" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/titleView"
|
||||
android:layout_width="wrap_content"
|
||||
style="@style/SudHeaderTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/restore_installing_packages"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageView" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progressBar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="4dp"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:indeterminate="false"
|
||||
app:layout_constraintBottom_toTopOf="@+id/appList"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/backupNameView"
|
||||
tools:max="23"
|
||||
tools:progress="5" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/backupNameView"
|
||||
style="@style/SudDescription"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:textColor="?android:textColorTertiary"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/titleView"
|
||||
tools:text="Pixel 2 XL" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/appList"
|
||||
style="@style/SudContent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/button"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
@ -68,17 +67,14 @@
|
|||
|
||||
<Button
|
||||
android:id="@+id/button"
|
||||
style="@style/ActionPrimaryButton"
|
||||
style="@style/SudPrimaryButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:enabled="false"
|
||||
android:text="@string/restore_next"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="1.0"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/appList" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
style="@style/SudHeaderIcon"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_cloud_download"
|
||||
|
|
@ -19,22 +16,21 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/titleView"
|
||||
android:layout_width="wrap_content"
|
||||
style="@style/SudHeaderTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:text="@string/restore_choose_restore_set"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageView" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/listView"
|
||||
style="@style/SudContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintBottom_toTopOf="@+id/skipView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
@ -54,9 +50,9 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/errorView"
|
||||
style="@style/SudContent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:textColor="?android:colorError"
|
||||
android:textSize="18sp"
|
||||
android:visibility="invisible"
|
||||
|
|
@ -69,15 +65,13 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/skipView"
|
||||
style="@style/SudSecondaryButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:padding="16dp"
|
||||
android:layout_marginStart="40dp"
|
||||
android:text="@string/restore_skip_apps"
|
||||
android:textColor="?android:colorAccent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/listView" />
|
||||
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
style="@style/SudHeaderIcon"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_storage"
|
||||
|
|
@ -19,11 +16,9 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/titleView"
|
||||
style="@style/SudHeaderTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageView"
|
||||
|
|
@ -31,10 +26,9 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/patienceView"
|
||||
style="@style/SudContent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="@string/storage_check_fragment_patience"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
@ -45,9 +39,9 @@
|
|||
style="?android:progressBarStyleLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/backButton"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
@ -56,11 +50,9 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/errorView"
|
||||
style="@style/SudContent"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:textColor="?android:colorError"
|
||||
android:textSize="18sp"
|
||||
android:visibility="invisible"
|
||||
|
|
@ -74,10 +66,10 @@
|
|||
|
||||
<Button
|
||||
android:id="@+id/backButton"
|
||||
style="@style/ActionPrimaryButton"
|
||||
style="@style/SudSecondaryButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_marginStart="40dp"
|
||||
android:text="@string/storage_check_fragment_error_button"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
style="@style/SudHeaderIcon"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_storage"
|
||||
|
|
@ -19,12 +16,10 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/titleView"
|
||||
style="@style/SudHeaderTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/storage_fragment_backup_title"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/imageView"
|
||||
|
|
@ -34,7 +29,7 @@
|
|||
android:id="@+id/warningIcon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginStart="40dp"
|
||||
android:src="@drawable/ic_warning"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/warningText"
|
||||
|
|
@ -49,7 +44,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:text="@string/storage_fragment_warning"
|
||||
android:textSize="16sp"
|
||||
android:visibility="gone"
|
||||
|
|
@ -58,27 +53,16 @@
|
|||
app:layout_constraintTop_toBottomOf="@+id/titleView"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:background="@color/divider"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/warningText"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/listView"
|
||||
style="@style/SudContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintBottom_toTopOf="@+id/skipView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/divider"
|
||||
app:layout_constraintTop_toBottomOf="@+id/warningText"
|
||||
app:layout_goneMarginTop="16dp"
|
||||
tools:listitem="@layout/list_item_storage_root" />
|
||||
|
||||
|
|
@ -94,16 +78,15 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/skipView"
|
||||
style="@style/SudSecondaryButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="40dp"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:padding="16dp"
|
||||
android:text="@string/restore_skip"
|
||||
android:textColor="?android:colorAccent"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/listView"
|
||||
tools:visibility="visible" />
|
||||
|
|
|
|||
|
|
@ -7,10 +7,7 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_margin="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
style="@style/SudHeaderIcon"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_cloud_download"
|
||||
|
|
@ -19,12 +16,10 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/titleView"
|
||||
style="@style/SudHeaderTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/restore_storage_choose_snapshot"
|
||||
android:textSize="24sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingStart="40dp"
|
||||
android:paddingEnd="40dp"
|
||||
android:textColor="?android:textColorPrimary"
|
||||
tools:text="@string/backup_section_not_allowed" />
|
||||
|
|
|
|||
|
|
@ -4,21 +4,22 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:background="?android:selectableItemBackground"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="8dp">
|
||||
android:paddingBottom="8dp"
|
||||
android:screenReaderFocusable="true">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/appIcon"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="fitCenter"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:srcCompat="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
|
|
@ -72,6 +73,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:visibility="invisible"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="40dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:background="?android:selectableItemBackground"
|
||||
tools:showIn="@layout/fragment_restore_set">
|
||||
|
||||
|
|
@ -11,7 +13,6 @@
|
|||
android:id="@+id/imageView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
android:id="@+id/iconView"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
|
|
@ -25,7 +24,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintBottom_toTopOf="@+id/summaryView"
|
||||
|
|
@ -41,7 +40,7 @@
|
|||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:textColor="?android:attr/textColorTertiary"
|
||||
android:textSize="12sp"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<resources>
|
||||
<color name="accent">@*android:color/accent_device_default_dark</color>
|
||||
<color name="primary">@*android:color/primary_device_default_settings</color>
|
||||
<color name="primaryDark">@*android:color/primary_dark_device_default_settings</color>
|
||||
<color name="primaryDark">@android:color/black</color>
|
||||
<color name="background">@color/primaryDark</color>
|
||||
<color name="actionBarPrimary">@color/background</color>
|
||||
<color name="statusBarColor">@android:color/transparent</color>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<color name="primaryDark">@*android:color/primary_dark_device_default_settings_light</color>
|
||||
<color name="background">@*android:color/background_device_default_light</color>
|
||||
<color name="actionBarPrimary">@*android:color/primary_device_default_light</color>
|
||||
<color name="statusBarColor">@*android:color/primary_dark_material_light_light_status_bar
|
||||
<color name="statusBarColor">@*android:color/primary_device_default_settings_light
|
||||
</color>
|
||||
<color name="red">@*android:color/error_color_device_default_dark</color>
|
||||
<color name="divider">#20ffffff</color>
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@
|
|||
<string name="notification_channel_title">Backup notification</string>
|
||||
<string name="notification_title">Backup running…</string>
|
||||
<string name="notification_backup_already_running">Backup already in progress…</string>
|
||||
<string name="notification_backup_disabled">Auto-backups off</string>
|
||||
|
||||
<string name="notification_success_title">Backup finished</string>
|
||||
<string name="notification_success_text">%1$d of %2$d apps backed up. Tap to learn more.</string>
|
||||
|
|
@ -140,6 +141,9 @@
|
|||
<!-- This text gets shown for apps that the OS did not try to back up for whatever reason e.g. no backup was run yet -->
|
||||
<string name="backup_app_not_yet_backed_up">Waiting to back up…</string>
|
||||
<string name="restore_app_not_yet_backed_up">Was not yet backed up</string>
|
||||
<string name="backup_app_in_progress">Backing up</string>
|
||||
<string name="backup_app_success">Backed up</string>
|
||||
<string name="backup_app_warning">Backup warning</string>
|
||||
<string name="backup_app_was_stopped">Not backed up as it wasn\'t used recently</string>
|
||||
<string name="restore_app_was_stopped">Was not backed up as it hadn\'t been used recently</string>
|
||||
<string name="backup_app_no_data">The app reported no data for backup</string>
|
||||
|
|
@ -160,6 +164,12 @@
|
|||
<string name="restore_set_error">An error occurred while loading the backups.</string>
|
||||
<string name="restore_set_empty_result">No suitable backups found at the given location.\n\nMost likely the recovery code is wrong, or there is a storage error.</string>
|
||||
<string name="restore_installing_packages">Re-installing apps</string>
|
||||
<string name="restore_app_status_installing">Re-installing</string>
|
||||
<string name="restore_app_status_installed">Re-installed</string>
|
||||
<string name="restore_app_status_install_error">Could not install</string>
|
||||
<string name="restore_app_status_restored">Data restored</string>
|
||||
<string name="restore_app_status_failed">Restore failed</string>
|
||||
<string name="restore_app_status_warning">Restore warning</string>
|
||||
<string name="restore_installing_error_title">Some apps not installed</string>
|
||||
<string name="restore_installing_error_message">Data can only be restored if an app is installed.\n\nTap failed apps to try to install them manually before proceeding.</string>
|
||||
<string name="restore_installing_tap_to_install">Tap to install</string>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@
|
|||
<item name="android:windowLightStatusBar">@bool/isLight</item>
|
||||
<item name="android:statusBarColor">@color/statusBarColor</item>
|
||||
<item name="actionBarTheme">@style/Theme.ActionBar</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowLightNavigationBar">@bool/isLight</item>
|
||||
<item name="android:navigationBarColor">@color/primary</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.ActionBar" parent="Theme.AppCompat.DayNight.DarkActionBar">
|
||||
|
|
@ -26,4 +27,84 @@
|
|||
<!-- Copied from Settings -->
|
||||
<style name="ActionPrimaryButton" parent="android:Widget.DeviceDefault.Button.Colored" />
|
||||
|
||||
<style name="SudHeaderTitle">
|
||||
<item name="android:ellipsize">end</item>
|
||||
<item name="android:maxLines">3</item>
|
||||
<item name="android:textSize">36sp</item>
|
||||
<item name="android:layout_marginBottom">16dp</item>
|
||||
<item name="android:layout_marginLeft">40dp</item>
|
||||
<item name="android:layout_marginRight">40dp</item>
|
||||
<item name="android:lineSpacingExtra">3.67sp</item>
|
||||
<item name="android:paddingBottom">2dp</item>
|
||||
<item name="android:paddingTop">16dp</item>
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="SudIconContainer">
|
||||
<item name="android:layout_marginLeft">40dp</item>
|
||||
<item name="android:layout_marginRight">40dp</item>
|
||||
<item name="android:layout_marginTop">56dp</item>
|
||||
<item name="android:maxHeight">32dp</item>
|
||||
</style>
|
||||
|
||||
<style name="SudHeaderIcon">
|
||||
<item name="android:layout_marginLeft">40dp</item>
|
||||
<item name="android:layout_marginRight">40dp</item>
|
||||
<item name="android:layout_marginTop">32dp</item>
|
||||
<item name="android:layout_width">48dp</item>
|
||||
<item name="android:layout_height">48dp</item>
|
||||
<item name="android:scaleType">fitCenter</item>
|
||||
<item name="android:adjustViewBounds">true</item>
|
||||
</style>
|
||||
|
||||
<style name="SudDescription">
|
||||
<item name="android:layout_gravity">top</item>
|
||||
<item name="android:layout_marginTop">3dp</item>
|
||||
<item name="android:layout_marginBottom">12dp</item>
|
||||
<item name="android:layout_marginLeft">40dp</item>
|
||||
<item name="android:layout_marginStart">40dp</item>
|
||||
<item name="android:layout_marginRight">40dp</item>
|
||||
<item name="android:layout_marginEnd">40dp</item>
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
<item name="android:textDirection">locale</item>
|
||||
<item name="android:gravity">start</item>
|
||||
<item name="android:textAlignment">gravity</item>
|
||||
<item name="android:lineSpacingExtra">3.67sp</item>
|
||||
</style>
|
||||
|
||||
<style name="SudContent" parent="SudDescription">
|
||||
<item name="android:layout_marginTop">32dp</item>
|
||||
<item name="android:layout_marginBottom">6dp</item>
|
||||
<item name="android:layout_marginStart">40dp</item>
|
||||
<item name="android:layout_marginEnd">40dp</item>
|
||||
<item name="android:gravity">start</item>
|
||||
<item name="android:textAlignment">gravity</item>
|
||||
</style>
|
||||
|
||||
<style name="SudPrimaryButton" parent="Widget.AppCompat.Button.Colored">
|
||||
<item name="android:buttonStyle">@style/SudPrimaryButton</item>
|
||||
<item name="android:theme">@style/SudPrimaryButton</item>
|
||||
<item name="buttonStyle">@style/SudPrimaryButton</item>
|
||||
<item name="android:paddingLeft">16dp</item>
|
||||
<item name="android:paddingRight">16dp</item>
|
||||
<item name="android:layout_marginTop">16dp</item>
|
||||
<item name="android:layout_marginBottom">16dp</item>
|
||||
<item name="android:stateListAnimator">@null</item>
|
||||
<item name="android:buttonCornerRadius">28dp</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:minHeight">56dp</item>
|
||||
<item name="textAllCaps">false</item>
|
||||
</style>
|
||||
|
||||
<style name="SudSecondaryButton" parent="Widget.AppCompat.Button.Borderless.Colored">
|
||||
<item name="android:buttonStyle">@style/SudSecondaryButton</item>
|
||||
<item name="android:theme">@style/SudSecondaryButton</item>
|
||||
<item name="buttonStyle">@style/SudSecondaryButton</item>
|
||||
<item name="android:paddingLeft">16dp</item>
|
||||
<item name="android:paddingRight">16dp</item>
|
||||
<item name="android:layout_marginTop">16dp</item>
|
||||
<item name="android:layout_marginBottom">16dp</item>
|
||||
<item name="android:minHeight">56dp</item>
|
||||
<item name="textAllCaps">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ internal class ApkBackupRestoreTest : TransportTest() {
|
|||
every { metadataManager.salt } returns salt
|
||||
every { crypto.getNameForApk(salt, packageName) } returns name
|
||||
every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName
|
||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||
|
||||
apkBackup.backupApkIfNecessary(packageInfo, PackageState.APK_AND_DATA, outputStreamGetter)
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@ internal class ApkRestoreTest : TransportTest() {
|
|||
every { strictContext.cacheDir } returns File(tmpDir.toString())
|
||||
every { crypto.getNameForApk(salt, packageName, "") } returns name
|
||||
coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream
|
||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||
|
||||
apkRestore.restore(backup).collectIndexed { i, value ->
|
||||
assertQueuedFailFinished(i, value)
|
||||
|
|
@ -112,6 +113,7 @@ internal class ApkRestoreTest : TransportTest() {
|
|||
every { crypto.getNameForApk(salt, packageName, "") } returns name
|
||||
coEvery { storagePlugin.getInputStream(token, name) } returns apkInputStream
|
||||
every { pm.getPackageArchiveInfo(any(), any()) } returns packageInfo
|
||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||
|
||||
apkRestore.restore(backup).collectIndexed { i, value ->
|
||||
assertQueuedFailFinished(i, value)
|
||||
|
|
@ -124,6 +126,7 @@ internal class ApkRestoreTest : TransportTest() {
|
|||
coEvery {
|
||||
apkInstaller.install(match { it.size == 1 }, packageName, installerName, any())
|
||||
} throws SecurityException()
|
||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||
|
||||
apkRestore.restore(backup).collectIndexed { i, value ->
|
||||
assertQueuedProgressFailFinished(i, value)
|
||||
|
|
@ -146,6 +149,7 @@ internal class ApkRestoreTest : TransportTest() {
|
|||
coEvery {
|
||||
apkInstaller.install(match { it.size == 1 }, packageName, installerName, any())
|
||||
} returns installResult
|
||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||
|
||||
apkRestore.restore(backup).collectIndexed { i, value ->
|
||||
assertQueuedProgressSuccessFinished(i, value)
|
||||
|
|
@ -184,6 +188,7 @@ internal class ApkRestoreTest : TransportTest() {
|
|||
coEvery {
|
||||
apkInstaller.install(match { it.size == 1 }, packageName, installerName, any())
|
||||
} returns installResult
|
||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||
|
||||
apkRestore.restore(backup).collectIndexed { i, value ->
|
||||
assertQueuedProgressSuccessFinished(i, value)
|
||||
|
|
@ -202,6 +207,7 @@ internal class ApkRestoreTest : TransportTest() {
|
|||
|
||||
cacheBaseApkAndGetInfo(tmpDir)
|
||||
every { packageInfo.applicationInfo.loadIcon(pm) } returns icon
|
||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||
|
||||
if (willFail) {
|
||||
every {
|
||||
|
|
@ -281,6 +287,7 @@ internal class ApkRestoreTest : TransportTest() {
|
|||
every {
|
||||
splitCompatChecker.isCompatible(deviceName, listOf(split1Name, split2Name))
|
||||
} returns false
|
||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||
|
||||
apkRestore.restore(backup).collectIndexed { i, value ->
|
||||
assertQueuedProgressFailFinished(i, value)
|
||||
|
|
@ -303,6 +310,7 @@ internal class ApkRestoreTest : TransportTest() {
|
|||
coEvery {
|
||||
storagePlugin.getInputStream(token, suffixName)
|
||||
} returns ByteArrayInputStream(getRandomByteArray())
|
||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||
|
||||
apkRestore.restore(backup).collectIndexed { i, value ->
|
||||
assertQueuedProgressFailFinished(i, value)
|
||||
|
|
@ -325,6 +333,7 @@ internal class ApkRestoreTest : TransportTest() {
|
|||
every { splitCompatChecker.isCompatible(deviceName, listOf(splitName)) } returns true
|
||||
every { crypto.getNameForApk(salt, packageName, splitName) } returns suffixName
|
||||
coEvery { storagePlugin.getInputStream(token, suffixName) } throws IOException()
|
||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||
|
||||
apkRestore.restore(backup).collectIndexed { i, value ->
|
||||
assertQueuedProgressFailFinished(i, value)
|
||||
|
|
@ -363,6 +372,7 @@ internal class ApkRestoreTest : TransportTest() {
|
|||
coEvery { storagePlugin.getInputStream(token, suffixName1) } returns split1InputStream
|
||||
every { crypto.getNameForApk(salt, packageName, split2Name) } returns suffixName2
|
||||
coEvery { storagePlugin.getInputStream(token, suffixName2) } returns split2InputStream
|
||||
every { storagePlugin.providerPackageName } returns storageProviderPackageName
|
||||
|
||||
coEvery {
|
||||
apkInstaller.install(match { it.size == 3 }, packageName, installerName, any())
|
||||
|
|
@ -381,6 +391,27 @@ internal class ApkRestoreTest : TransportTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `storage provider app does not get reinstalled`(@TempDir tmpDir: Path) = runBlocking {
|
||||
// set the storage provider package name to match our current package name,
|
||||
// and ensure that the current package is therefore skipped.
|
||||
every { storagePlugin.providerPackageName } returns packageName
|
||||
|
||||
apkRestore.restore(backup).collectIndexed { i, value ->
|
||||
when (i) {
|
||||
0 -> {
|
||||
assertFalse(value.isFinished)
|
||||
}
|
||||
1 -> {
|
||||
// the only package provided should have been filtered, leaving 0 packages.
|
||||
assertEquals(0, value.total)
|
||||
assertTrue(value.isFinished)
|
||||
}
|
||||
else -> fail("more values emitted")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun swapPackages(packageMetadataMap: PackageMetadataMap): RestorableBackup {
|
||||
val metadata = metadata.copy(packageMetadataMap = packageMetadataMap)
|
||||
return backup.copy(backupMetadata = metadata)
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ internal abstract class TransportTest {
|
|||
protected val salt = metadata.salt
|
||||
protected val name = getRandomString(12)
|
||||
protected val name2 = getRandomString(23)
|
||||
protected val storageProviderPackageName = getRandomString(23)
|
||||
|
||||
init {
|
||||
mockkStatic(Log::class)
|
||||
|
|
|
|||
26
storage/artwork/ic_cloud_restore.svg
Normal file
26
storage/artwork/ic_cloud_restore.svg
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" height="24" viewBox="0 0 24 24"
|
||||
width="24" version="1.1" id="svg6" sodipodi:docname="cloud-24px.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata id="metadata12">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs id="defs10" />
|
||||
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1"
|
||||
objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2" inkscape:window-width="1920" inkscape:window-height="958"
|
||||
id="namedview8" showgrid="false" inkscape:zoom="13.007819" inkscape:cx="14.342117"
|
||||
inkscape:cy="11.405653" inkscape:window-x="1920" inkscape:window-y="96"
|
||||
inkscape:window-maximized="0" inkscape:current-layer="svg6" />
|
||||
<path d="M0 0h24v24H0z" fill="none" id="path2" />
|
||||
<path id="path4"
|
||||
d="M 12 4 C 9.11 4 6.5996094 5.6390625 5.3496094 8.0390625 C 2.3396094 8.3590625 -1.1842379e-15 10.91 0 14 C 0 17.31 2.69 20 6 20 L 19 20 C 21.76 20 24 17.76 24 15 C 24 12.36 21.949609 10.219062 19.349609 10.039062 C 18.669609 6.5890625 15.64 4 12 4 z M 12.175781 8.1230469 C 14.93578 8.1230469 17.175781 10.363047 17.175781 13.123047 C 17.175781 15.883047 14.93578 18.123047 12.175781 18.123047 C 10.125781 18.123047 8.365703 16.883047 7.5957031 15.123047 L 9.3066406 15.123047 C 9.9366406 16.023047 10.985781 16.623047 12.175781 16.623047 C 14.105781 16.623047 15.675781 15.053047 15.675781 13.123047 C 15.675781 11.193047 14.105781 9.6230469 12.175781 9.6230469 C 10.825781 9.6230469 9.6561719 10.401484 9.0761719 11.521484 L 10.675781 13.123047 L 6.6757812 13.123047 L 6.6757812 9.1230469 L 7.9765625 10.421875 C 8.8665625 9.0418743 10.405781 8.1230469 12.175781 8.1230469 z " />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
27
storage/artwork/ic_download_library.svg
Normal file
27
storage/artwork/ic_download_library.svg
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" width="24"
|
||||
height="24" viewBox="0 0 24 24" id="svg4" sodipodi:docname="image-multiple.svg"
|
||||
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
|
||||
<metadata id="metadata10">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs id="defs8" />
|
||||
<sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1"
|
||||
objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2" inkscape:window-width="1920" inkscape:window-height="958"
|
||||
id="namedview6" showgrid="false" inkscape:zoom="13.007819" inkscape:cx="8.8546913"
|
||||
inkscape:cy="7.0282265" inkscape:window-x="1920" inkscape:window-y="96"
|
||||
inkscape:window-maximized="0" inkscape:current-layer="svg4" />
|
||||
<path id="path1490"
|
||||
d="M 2 6 L 2 20 C 2 21.104569 2.8954305 22 4 22 L 18 22 L 18 20 L 4 20 L 4 6 L 2 6 z " />
|
||||
<path id="path1486"
|
||||
d="M 8 2 C 6.8954305 2 6 2.8954305 6 4 L 6 16 C 6 17.104569 6.8954305 18 8 18 L 20 18 C 21.104569 18 22 17.104569 22 16 L 22 4 C 22 2.8954305 21.104569 2 20 2 L 8 2 z M 12.5 5 L 15.5 5 L 15.5 8 L 18 8 L 14 12 L 10 8 L 12.5 8 L 12.5 5 z M 10 13 L 18 13 L 18 15 L 10 15 L 10 13 z " />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -57,9 +57,9 @@ public abstract class BackupContentFragment : Fragment(), ContentClickListener {
|
|||
|
||||
val adapter = BackupContentAdapter(this)
|
||||
list.adapter = adapter
|
||||
viewModel.content.observe(viewLifecycleOwner, {
|
||||
viewModel.content.observe(viewLifecycleOwner) {
|
||||
adapter.setItems(it)
|
||||
})
|
||||
}
|
||||
v.findViewById<FloatingActionButton>(R.id.fab).setOnClickListener {
|
||||
addRequest.launch(DocumentsContract.buildRootsUri(EXTERNAL_STORAGE_PROVIDER_AUTHORITY))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@
|
|||
android:id="@+id/list"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:padding="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingStart="40dp"
|
||||
android:paddingEnd="40dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bottomStub"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
@ -32,7 +35,7 @@
|
|||
android:id="@+id/emptyStateView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_margin="40dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/snapshots_empty"
|
||||
android:visibility="invisible"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:screenReaderFocusable="true"
|
||||
app:cardCornerRadius="8dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
|
|
@ -41,6 +43,7 @@
|
|||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/content_options"
|
||||
android:src="@drawable/ic_more_vert"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:screenReaderFocusable="true"
|
||||
app:cardCornerRadius="8dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:importantForAccessibility="no"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
app:cardCornerRadius="16dp"
|
||||
tools:showIn="@layout/fragment_snapshot">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
|
|
@ -13,14 +13,15 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:padding="8dp">
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/nameView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:layout_marginEnd="8dp"
|
||||
app:layout_constraintEnd_toStartOf="@+id/sizeView"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Backup name which might be quite long, who knows...?" />
|
||||
|
|
@ -41,11 +42,10 @@
|
|||
android:id="@+id/sizeView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="@+id/nameView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@+id/timeView"
|
||||
app:layout_constraintTop_toBottomOf="@+id/nameView"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="35 GB" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
<string name="content_videos">Videos</string>
|
||||
<string name="content_audio">Audio files</string>
|
||||
<string name="content_downloads">Downloads</string>
|
||||
<string name="content_options">Options</string>
|
||||
<string name="content_add">Add</string>
|
||||
|
||||
<string name="notification_backup_title">Storage backup</string>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue