diff --git a/WordPress/build.gradle b/WordPress/build.gradle index 802f8966cc96..dbd793a32013 100644 --- a/WordPress/build.gradle +++ b/WordPress/build.gradle @@ -422,6 +422,7 @@ dependencies { implementation(libs.androidx.lifecycle.livedata.core) implementation(libs.androidx.lifecycle.livedata.main) implementation(libs.androidx.lifecycle.process) + implementation(libs.androidx.startup.runtime) implementation(libs.android.volley) implementation(libs.google.play.review) implementation(libs.google.mlkit.barcode.scanning.common) diff --git a/WordPress/proguard.cfg b/WordPress/proguard.cfg index c408aff90ed8..3843ae7ea7af 100644 --- a/WordPress/proguard.cfg +++ b/WordPress/proguard.cfg @@ -153,3 +153,9 @@ -dontwarn com.google.re2j.Matcher -dontwarn com.google.re2j.Pattern ###### jsoup - end + +###### Gravatar Quick Editor - begin +# The library's startup initializer is removed from the manifest and run on demand by class name (see +# GravatarQuickEditorInitializer), so keep it even if startup-runtime's own consumer rules ever change. +-keep class com.gravatar.quickeditor.initializer.QuickEditorContainerInitializer { (); } +###### Gravatar Quick Editor - end diff --git a/WordPress/src/androidTest/java/org/wordpress/android/InitializationRule.kt b/WordPress/src/androidTest/java/org/wordpress/android/InitializationRule.kt index 8759b9bc9e66..fa76a763cd16 100644 --- a/WordPress/src/androidTest/java/org/wordpress/android/InitializationRule.kt +++ b/WordPress/src/androidTest/java/org/wordpress/android/InitializationRule.kt @@ -5,6 +5,7 @@ import dagger.hilt.EntryPoint import dagger.hilt.EntryPoints import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import kotlinx.coroutines.runBlocking import org.junit.rules.TestRule import org.junit.runner.Description import org.junit.runners.model.Statement @@ -27,6 +28,9 @@ class InitializationRule : TestRule { AppInitializerEntryPoint::class.java ).appInitializer() instrumentation.runOnMainSync { appInitializer.init() } + // init() enqueues the periodic upload work asynchronously; wait for it so the enqueue lands in + // the real WorkManager before a test swaps in WorkManagerTestInitHelper's instance. + runBlocking { appInitializer.periodicUploadEnqueueJob?.join() } application.initializer = appInitializer diff --git a/WordPress/src/androidTest/java/org/wordpress/android/TestUtils.java b/WordPress/src/androidTest/java/org/wordpress/android/TestUtils.java index b0491104cb85..55fd855344d0 100644 --- a/WordPress/src/androidTest/java/org/wordpress/android/TestUtils.java +++ b/WordPress/src/androidTest/java/org/wordpress/android/TestUtils.java @@ -3,18 +3,12 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; -import android.database.sqlite.SQLiteDatabase; -import android.text.TextUtils; import androidx.preference.PreferenceManager; import org.greenrobot.eventbus.EventBus; import org.wordpress.android.util.DateTimeUtils; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.lang.reflect.Field; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -24,49 +18,11 @@ import java.util.Locale; import java.util.Map; -import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; public class TestUtils { private static final String DATABASE_NAME = "wordpress"; - public static SQLiteDatabase loadDBFromDump(Context targetContext, Context testContext, String filename) { - targetContext.deleteDatabase(DATABASE_NAME); - WordPress.wpDB = new WordPressDB(targetContext); - - Field dbField; - try { - dbField = WordPressDB.class.getDeclaredField("db"); - dbField.setAccessible(true); - SQLiteDatabase db = (SQLiteDatabase) dbField.get(WordPress.wpDB); - assertNotNull(db); - - // Load file - InputStream is = testContext.getAssets().open(filename); - InputStreamReader inputStreamReader = new InputStreamReader(is); - BufferedReader f = new BufferedReader(inputStreamReader); - for (String line = f.readLine(); line != null; line = f.readLine()) { - if (TextUtils.isEmpty(line)) { - continue; - } - try { - db.execSQL(line); - } catch (android.database.sqlite.SQLiteException e) { - // ignore import errors - } - } - f.close(); - return db; - } catch (NoSuchFieldException e) { - assertTrue(e.toString(), false); - } catch (IllegalAccessException e) { - assertTrue(e.toString(), false); - } catch (IOException e) { - assertTrue(e.toString(), false); - } - return null; - } - public static void resetEventBus() { Field dbField; try { diff --git a/WordPress/src/main/AndroidManifest.xml b/WordPress/src/main/AndroidManifest.xml index 2ce7833dc6dc..955173a0f633 100644 --- a/WordPress/src/main/AndroidManifest.xml +++ b/WordPress/src/main/AndroidManifest.xml @@ -1389,8 +1389,25 @@ android:name="androidx.work.WorkManagerInitializer" android:value="androidx.startup" tools:node="remove" /> + + + + + + Unit): Job = + appScope.launch(ioDispatcher) { + try { + block() + } catch (e: Exception) { + AppLog.e(tag, failureMessage, e) + } + } + + /** + * Enqueues our periodic upload work request, which uploads local drafts or published posts with local + * changes even when the app is closed. Runs off the main thread because the first WorkManager access + * initializes it on demand (see [WordPress.workManagerConfiguration]), which opens its Room database. + */ + private fun enqueuePeriodicUploadWorkAsync() { + periodicUploadEnqueueJob = launchIo(T.MAIN, "Failed to enqueue periodic upload work") { + enqueuePeriodicUploadWorkRequestForAllSites() } - configBuilder.setJobSchedulerJobIdRange(WORK_MANAGER_ID_RANGE_MIN, WORK_MANAGER_ID_RANGE_MAX) - WorkManager.initialize(application, configBuilder.build()) + } + + /** + * Opens the legacy app database off the main thread so that the first main-thread reader usually finds it + * ready. [WordPress.wpDB] is lazy and synchronized, so readers that get there first simply open it themselves. + */ + private fun warmUpWpDb() { + launchIo(T.DB, "Failed to open the app database") { WordPress.wpDB } } @Suppress("TooGenericExceptionCaught") @@ -461,11 +481,10 @@ class AppInitializer @Inject constructor( private fun sanitizeMediaUploadStateForSite() { val selectedSiteLocalId: Int = selectedSiteRepository.getSelectedSiteLocalId(true) - val site = siteStore.getSiteByLocalId(selectedSiteLocalId) - site?.let { - Thread { - UploadService.sanitizeMediaUploadStateForSite(mediaStore, dispatcher, site) - }.start() + launchIo(T.MEDIA, "Failed to sanitize the media upload state") { + // The site lookup is a database read (plus credential decryption), so keep it off the main thread + val site = siteStore.getSiteByLocalId(selectedSiteLocalId) ?: return@launchIo + UploadService.sanitizeMediaUploadStateForSite(mediaStore, dispatcher, site) } } @@ -584,28 +603,6 @@ class AppInitializer @Inject constructor( } } - private fun initWpDb() { - if (!createAndVerifyWpDb()) { - AppLog.e(T.DB, "Invalid database, sign out user and delete database") - // Force DB deletion - WordPressDB.deleteDatabase(application) - WordPress.wpDB = WordPressDB(application) - } - } - - private fun createAndVerifyWpDb(): Boolean { - return try { - WordPress.wpDB = WordPressDB(application) - true - } catch (e: SQLiteException) { - AppLog.e(T.DB, e) - false - } catch (e: SQLException) { - AppLog.e(T.DB, e) - false - } - } - /** * Sign out from wpcom account. * Note: This method must not be called on UI Thread. @@ -966,11 +963,6 @@ class AppInitializer @Inject constructor( private const val MEMORY_CACHE_RATIO = 0.25 // Use 1/4th of the available memory for memory cache. private const val DEFAULT_TIMEOUT = 2 * 60 // 2 minutes - // Use service ids near the int max to avoid collisions with existing JobService ids - // The minimum range size is 1000, but we can easily give 10000. - private const val WORK_MANAGER_ID_RANGE_MAX = Int.MAX_VALUE - private const val WORK_MANAGER_ID_RANGE_MIN = WORK_MANAGER_ID_RANGE_MAX - 10000 - @SuppressLint("StaticFieldLeak") var context: Context? = null private set diff --git a/WordPress/src/main/java/org/wordpress/android/WordPress.kt b/WordPress/src/main/java/org/wordpress/android/WordPress.kt index 8ec8a90916c7..d6811cfdf8da 100644 --- a/WordPress/src/main/java/org/wordpress/android/WordPress.kt +++ b/WordPress/src/main/java/org/wordpress/android/WordPress.kt @@ -1,7 +1,11 @@ package org.wordpress.android import android.app.Application +import android.content.Context +import android.database.SQLException import android.os.Build +import android.util.Log +import androidx.work.Configuration import coil.decode.VideoFrameDecoder import com.android.volley.RequestQueue import dagger.hilt.EntryPoints @@ -9,14 +13,27 @@ import okhttp3.OkHttpClient import org.wordpress.android.fluxc.tools.FluxCImageLoader import org.wordpress.android.modules.AppComponent import org.wordpress.android.ui.main.EdgeToEdgeActivityLifecycleCallbacks +import org.wordpress.android.util.AppLog +import org.wordpress.android.util.AppLog.T /** * An abstract class to be extended by {@link WordPressApp} for real application and WordPressTest for UI test * application. Containing public static variables and methods to be accessed by other classes. */ -abstract class WordPress : Application(), coil.ImageLoaderFactory { +abstract class WordPress : Application(), coil.ImageLoaderFactory, Configuration.Provider { abstract fun initializer(): AppInitializer + /** + * WorkManager is initialized on demand (the default initializer is removed in the manifest) so that its + * Room database is opened by whichever thread first needs it, off the main thread on normal process starts. + */ + override val workManagerConfiguration: Configuration + get() = Configuration.Builder() + .setWorkerFactory(component().wordPressWorkersFactory()) + .setJobSchedulerJobIdRange(WORK_MANAGER_ID_RANGE_MIN, WORK_MANAGER_ID_RANGE_MAX) + .apply { if (BuildConfig.DEBUG) setMinimumLoggingLevel(Log.DEBUG) } + .build() + override fun onCreate() { super.onCreate() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { @@ -63,19 +80,37 @@ abstract class WordPress : Application(), coil.ImageLoaderFactory { const val REMOTE_SITE_ID = "REMOTE_SITE_ID" const val USER_AGENT_APPNAME = "wp-android" + // Use service ids near the int max to avoid collisions with existing JobService ids + // The minimum range size is 1000, but we can easily give 10000. + private const val WORK_MANAGER_ID_RANGE_MAX = Int.MAX_VALUE + private const val WORK_MANAGER_ID_RANGE_MIN = WORK_MANAGER_ID_RANGE_MAX - 10000 + lateinit var versionName: String - lateinit var wpDB: WordPressDB var appIsInTheBackground = true + /** + * The legacy app database. Opened lazily (and warmed up off the main thread by [AppInitializer]) so + * that background process starts don't run the SQLite open + migrations on the main thread. + */ + @JvmStatic + val wpDB: WordPressDB by lazy { openWpDb(getContext()) } + + private fun openWpDb(context: Context): WordPressDB { + return try { + WordPressDB(context) + } catch (e: SQLException) { + AppLog.e(T.DB, "Invalid database, deleting and recreating it", e) + WordPressDB.deleteDatabase(context) + WordPressDB(context) + } + } + @JvmField var requestQueue: RequestQueue? = null @JvmField var imageLoader: FluxCImageLoader? = null - val isWpDBInitialized - get() = ::wpDB.isInitialized - @JvmStatic fun getBitmapCache() = AppInitializer.getBitmapCache() diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/NotificationsTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/NotificationsTable.java index 890ca77e99c6..2c21509b1397 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/NotificationsTable.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/NotificationsTable.java @@ -25,7 +25,7 @@ public class NotificationsTable { private static final String NOTIFICATIONS_TABLE = "tbl_notifications"; private static SQLiteDatabase getDb() { - return WordPress.wpDB.getDatabase(); + return WordPress.getWpDB().getDatabase(); } public static final int NOTES_TO_RETRIEVE = 200; diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/PeopleTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/PeopleTable.java index b02fcdf85875..0aecc6547602 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/PeopleTable.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/PeopleTable.java @@ -23,11 +23,11 @@ public class PeopleTable { private static final String VIEWERS_TABLE = "people_viewers"; private static SQLiteDatabase getReadableDb() { - return WordPress.wpDB.getDatabase(); + return WordPress.getWpDB().getDatabase(); } private static SQLiteDatabase getWritableDb() { - return WordPress.wpDB.getDatabase(); + return WordPress.getWpDB().getDatabase(); } public static void createTables(SQLiteDatabase db) { diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/PublicizeTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/PublicizeTable.java index 52968d43263e..8bbc263ede18 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/PublicizeTable.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/PublicizeTable.java @@ -51,11 +51,11 @@ public static void createTables(SQLiteDatabase db) { } private static SQLiteDatabase getReadableDb() { - return WordPress.wpDB.getDatabase(); + return WordPress.getWpDB().getDatabase(); } private static SQLiteDatabase getWritableDb() { - return WordPress.wpDB.getDatabase(); + return WordPress.getWpDB().getDatabase(); } public static void resetServicesTable(SQLiteDatabase db) { diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/SiteSettingsTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/SiteSettingsTable.java index 0ac3dca08af1..a152370a9df6 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/SiteSettingsTable.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/SiteSettingsTable.java @@ -48,7 +48,7 @@ public static void addSharingColumnsToSiteSettingsTable(SQLiteDatabase db) { public static SparseArrayCompat getAllCategories() { String sqlCommand = sqlSelectAllCategories() + ";"; - Cursor cursor = WordPress.wpDB.getDatabase().rawQuery(sqlCommand, null); + Cursor cursor = WordPress.getWpDB().getDatabase().rawQuery(sqlCommand, null); try { if (cursor == null || !cursor.moveToFirst() || cursor.getCount() == 0) { return null; @@ -77,7 +77,7 @@ public static Cursor getSettings(long id) { String whereClause = sqlWhere(SiteSettingsModel.ID_COLUMN_NAME, Long.toString(id)); String sqlCommand = sqlSelectAllSettings() + whereClause + ";"; - return WordPress.wpDB.getDatabase().rawQuery(sqlCommand, null); + return WordPress.getWpDB().getDatabase().rawQuery(sqlCommand, null); } public static void saveCategory(CategoryModel category) { @@ -86,7 +86,7 @@ public static void saveCategory(CategoryModel category) { } ContentValues values = category.serializeToDatabase(); - category.isInLocalTable = WordPress.wpDB.getDatabase().insertWithOnConflict( + category.isInLocalTable = WordPress.getWpDB().getDatabase().insertWithOnConflict( CATEGORIES_TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE) != -1; } @@ -106,7 +106,7 @@ public static void saveSettings(SiteSettingsModel settings) { } ContentValues values = settings.serializeToDatabase(); - settings.isInLocalTable = WordPress.wpDB.getDatabase().insertWithOnConflict( + settings.isInLocalTable = WordPress.getWpDB().getDatabase().insertWithOnConflict( SiteSettingsModel.SETTINGS_TABLE_NAME, null, values, SQLiteDatabase.CONFLICT_REPLACE) != -1; saveCategories(settings.categories); diff --git a/WordPress/src/main/java/org/wordpress/android/datasets/UserSuggestionTable.java b/WordPress/src/main/java/org/wordpress/android/datasets/UserSuggestionTable.java index ae41b10f6533..80bfb6745ce3 100644 --- a/WordPress/src/main/java/org/wordpress/android/datasets/UserSuggestionTable.java +++ b/WordPress/src/main/java/org/wordpress/android/datasets/UserSuggestionTable.java @@ -45,11 +45,11 @@ public static void reset(SQLiteDatabase db) { } private static SQLiteDatabase getReadableDb() { - return WordPress.wpDB.getDatabase(); + return WordPress.getWpDB().getDatabase(); } private static SQLiteDatabase getWritableDb() { - return WordPress.wpDB.getDatabase(); + return WordPress.getWpDB().getDatabase(); } public static void insertSuggestionsForSite(final long siteId, final List suggestions) { diff --git a/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java b/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java index 7c9d265446b3..ddd3cd3445ed 100644 --- a/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java +++ b/WordPress/src/main/java/org/wordpress/android/modules/AppComponent.java @@ -175,6 +175,7 @@ import org.wordpress.android.ui.whatsnew.FeatureAnnouncementListAdapter; import org.wordpress.android.util.WPWebViewClient; import org.wordpress.android.util.image.getters.WPCustomImageGetter; +import org.wordpress.android.workers.WordPressWorkersFactory; import dagger.hilt.EntryPoint; import dagger.hilt.InstallIn; @@ -183,6 +184,8 @@ @InstallIn(SingletonComponent.class) @EntryPoint public interface AppComponent { + WordPressWorkersFactory wordPressWorkersFactory(); + void inject(WPMainActivity object); void inject(MediaUploadHandler object); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/AddQuickPressShortcutActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/AddQuickPressShortcutActivity.java index 53670b489e17..0535bca372c8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/AddQuickPressShortcutActivity.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/AddQuickPressShortcutActivity.java @@ -152,7 +152,7 @@ public void onClick(DialogInterface dialog, int which) { String shortcutName = quickPressShortcutName.getText().toString(); - WordPress.wpDB.addQuickPressShortcut(siteIds[position], shortcutName); + WordPress.getWpDB().addQuickPressShortcut(siteIds[position], shortcutName); ShortcutInfoCompat pinShortcutInfo = new ShortcutInfoCompat.Builder(getApplicationContext(), shortcutName) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/WPLaunchActivity.kt b/WordPress/src/main/java/org/wordpress/android/ui/WPLaunchActivity.kt index 7d9818663e8a..3e07232dd7ef 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/WPLaunchActivity.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/WPLaunchActivity.kt @@ -6,11 +6,9 @@ import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.wordpress.android.R -import org.wordpress.android.WordPress import org.wordpress.android.ui.main.WPMainActivity import org.wordpress.android.util.MissingSplitsUtils.isMissingSplits import org.wordpress.android.util.ProfilingUtils -import org.wordpress.android.util.ToastUtils @SuppressLint("CustomSplashScreen") class WPLaunchActivity : AppCompatActivity() { @@ -50,11 +48,6 @@ class WPLaunchActivity : AppCompatActivity() { } private fun launchWPMainActivity() { - if (!WordPress.isWpDBInitialized) { - ToastUtils.showToast(this, R.string.fatal_db_error, ToastUtils.Duration.LONG) - finish() - return - } val intent = Intent(this, WPMainActivity::class.java) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) intent.action = getIntent().action diff --git a/WordPress/src/main/java/org/wordpress/android/ui/main/MeFragment.kt b/WordPress/src/main/java/org/wordpress/android/ui/main/MeFragment.kt index 57d422ddb276..414b42831324 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/main/MeFragment.kt +++ b/WordPress/src/main/java/org/wordpress/android/ui/main/MeFragment.kt @@ -15,7 +15,9 @@ import androidx.compose.runtime.collectAsState import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import com.gravatar.quickeditor.GravatarQuickEditor @@ -28,6 +30,11 @@ import com.gravatar.quickeditor.ui.editor.GravatarQuickEditorParams import com.gravatar.quickeditor.ui.editor.QuickEditorScopeOption import com.gravatar.types.Email import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.Deferred +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.greenrobot.eventbus.EventBus import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode @@ -61,6 +68,7 @@ import org.wordpress.android.ui.prefs.AppPrefsWrapper import org.wordpress.android.ui.prefs.experimentalfeatures.ExperimentalFeatures import org.wordpress.android.ui.utils.UiString import org.wordpress.android.ui.utils.UiString.UiStringText +import org.wordpress.android.util.GravatarQuickEditorInitializer import org.wordpress.android.util.AppLog import org.wordpress.android.util.AppLog.T.MAIN import org.wordpress.android.util.FluxCUtils @@ -127,6 +135,9 @@ class MeFragment : Fragment(R.layout.me_fragment), OnScrollToTopListener { @Inject lateinit var appLogWrapper: AppLogWrapper + // Started in onCreate so the KeyStore-backed Gravatar init is usually finished before the avatar is tapped + private lateinit var quickEditorReady: Deferred + @Inject lateinit var activityNavigator: ActivityNavigator @@ -142,6 +153,10 @@ class MeFragment : Fragment(R.layout.me_fragment), OnScrollToTopListener { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) (requireActivity().application as WordPress).component().inject(this) + val appContext = requireContext().applicationContext + quickEditorReady = lifecycleScope.async(Dispatchers.IO) { + GravatarQuickEditorInitializer.initialize(appContext) + } } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -255,42 +270,53 @@ class MeFragment : Fragment(R.layout.me_fragment), OnScrollToTopListener { private fun MeFragmentBinding.showQuickEditor( page: AvatarPickerAndAboutEditorConfiguration.Page ) { - try { - appLogWrapper.d(AppLog.T.MAIN, "Gravatar: Showing Gravatar quick editor: ${page.value}") - GravatarQuickEditor.show( - fragment = this@MeFragment, - gravatarQuickEditorParams = GravatarQuickEditorParams { - email = Email(accountStore.account.email) - scopeOption = QuickEditorScopeOption.avatarAndAbout { - initialPage = page - fields = setOf( - AboutInputField.FirstName, - AboutInputField.LastName, - AboutInputField.DisplayName, - AboutInputField.AboutMe - ) - } - }, - authenticationMethod = AuthenticationMethod.Bearer(accountStore.accessToken.orEmpty()), - updateHandler = { event -> - when (event) { - AvatarPickerResult -> { - loadAvatar(null, true) + appLogWrapper.d(AppLog.T.MAIN, "Gravatar: Showing Gravatar quick editor: ${page.value}") + val appContext = requireContext().applicationContext + viewLifecycleOwner.lifecycleScope.launch { + // Complete except in the first moments of the fragment's life, so this almost never suspends. A + // warm-up that failed (e.g. a transient KeyStore error) gets one more try here. + val ready = quickEditorReady.await() || + withContext(Dispatchers.IO) { GravatarQuickEditorInitializer.initialize(appContext) } + if (!ready) return@launch + // A tap that did suspend could resume after the fragment left the screen + if (!viewLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) return@launch + try { + GravatarQuickEditor.show( + fragment = this@MeFragment, + gravatarQuickEditorParams = GravatarQuickEditorParams { + email = Email(accountStore.account.email) + scopeOption = QuickEditorScopeOption.avatarAndAbout { + initialPage = page + fields = setOf( + AboutInputField.FirstName, + AboutInputField.LastName, + AboutInputField.DisplayName, + AboutInputField.AboutMe + ) } - - is AboutEditorResult -> { - meDisplayName.text = event.profile.displayName.ifEmpty { accountStore.account.displayName } + }, + authenticationMethod = AuthenticationMethod.Bearer(accountStore.accessToken.orEmpty()), + updateHandler = { event -> + when (event) { + AvatarPickerResult -> { + loadAvatar(null, true) + } + + is AboutEditorResult -> { + meDisplayName.text = + event.profile.displayName.ifEmpty { accountStore.account.displayName } + } + + else -> Unit } - - else -> Unit + }, + onDismiss = { + appLogWrapper.d(AppLog.T.MAIN, "Gravatar: Gravatar quick editor dismissed: ${page.value}") } - }, - onDismiss = { - appLogWrapper.d(AppLog.T.MAIN, "Gravatar: Gravatar quick editor dismissed: ${page.value}") - } - ) - } catch (exception: Exception) { - appLogWrapper.d(AppLog.T.MAIN, "Gravatar: Error opening Gravatar quick editor: ${exception.message}") + ) + } catch (exception: Exception) { + appLogWrapper.d(AppLog.T.MAIN, "Gravatar: Error opening Gravatar quick editor: ${exception.message}") + } } } diff --git a/WordPress/src/main/java/org/wordpress/android/ui/notifications/receivers/NotificationsPendingDraftsReceiver.java b/WordPress/src/main/java/org/wordpress/android/ui/notifications/receivers/NotificationsPendingDraftsReceiver.java index 098dff1cb09c..45b0e1a91041 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/notifications/receivers/NotificationsPendingDraftsReceiver.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/notifications/receivers/NotificationsPendingDraftsReceiver.java @@ -53,26 +53,41 @@ public class NotificationsPendingDraftsReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { ((WordPress) context.getApplicationContext()).component().inject(this); - // for the case of being spanned after device restarts, get the latest drafts - // and check the lastUpdated - String action = intent.getAction(); - if (action != null && action.equals("android.intent.action.BOOT_COMPLETED")) { - AppLog.i(AppLog.T.NOTIFS, "entering Pending Drafts Receiver from BOOT_COMPLETED"); - // build notifications for existing local drafts - SiteModel site = mSiteStore.getSiteByLocalId(mSelectedSiteRepository.getSelectedSiteLocalId()); - if (site != null) { - List draftPosts = mPostStore.getPostsForSite(site); - for (PostModel post : draftPosts) { - // reschedule next notifications for each local draft post we have, as we have - // just been rebooted - PendingDraftsNotificationsUtils.scheduleNextNotifications(context, post.getId(), - post.getDateLocallyChanged()); + // Both branches read posts from the database. Doing that on the main thread inside a broadcast + // (in particular BOOT_COMPLETED, which starts the process in the background) shows up as ANRs, so + // the work is moved to a background thread and the broadcast is kept alive with goAsync(). + final boolean isBootCompleted = Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction()); + final int postId = intent.getIntExtra(POST_ID_EXTRA, 0); + final PendingResult pendingResult = goAsync(); + new Thread(() -> { + try { + if (isBootCompleted) { + AppLog.i(AppLog.T.NOTIFS, "entering Pending Drafts Receiver from BOOT_COMPLETED"); + rescheduleNotificationsForLocalDrafts(context); + } else { + AppLog.i(AppLog.T.NOTIFS, "entering Pending Drafts Receiver from alarm"); + buildNotificationForPostId(postId, context); } + } catch (Exception e) { + AppLog.e(AppLog.T.NOTIFS, "Pending Drafts Receiver failed", e); + } finally { + pendingResult.finish(); } - } else { - AppLog.i(AppLog.T.NOTIFS, "entering Pending Drafts Receiver from alarm"); - // get extras from intent in order to build notification - buildNotificationForPostId(intent.getIntExtra(POST_ID_EXTRA, 0), context); + }, "PendingDraftsReceiver").start(); + } + + /** + * After a reboot every alarm is gone, so reschedule the next notification for each local draft. + */ + private void rescheduleNotificationsForLocalDrafts(Context context) { + SiteModel site = mSiteStore.getSiteByLocalId(mSelectedSiteRepository.getSelectedSiteLocalId()); + if (site == null) { + return; + } + List draftPosts = mPostStore.getPostsForSite(site); + for (PostModel post : draftPosts) { + PendingDraftsNotificationsUtils.scheduleNextNotifications(context, post.getId(), + post.getDateLocallyChanged()); } } diff --git a/WordPress/src/main/java/org/wordpress/android/util/GravatarQuickEditorInitializer.kt b/WordPress/src/main/java/org/wordpress/android/util/GravatarQuickEditorInitializer.kt new file mode 100644 index 000000000000..73912799143c --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/util/GravatarQuickEditorInitializer.kt @@ -0,0 +1,43 @@ +package org.wordpress.android.util + +import android.content.Context +import androidx.startup.AppInitializer +import androidx.startup.Initializer +import org.wordpress.android.util.AppLog.T + +/** + * Initializes the Gravatar Quick Editor on demand. + * + * The library registers an androidx.startup initializer that builds an encrypted DataStore (AndroidKeyStore + + * Tink self-test) on the main thread before Application.onCreate, which showed up in Play Console as background + * ANRs on every process start. That initializer is removed in the manifest and run from here instead, only when + * the editor is actually about to be used. [AppInitializer.initializeComponent] is idempotent and synchronized, + * so this is safe to call repeatedly and from any thread. + * + * The initializer class is internal to the library, hence the lookup by name. WordPress/proguard.cfg keeps the + * class and its no-arg constructor so the lookup survives R8. + * + * Remove this (and the manifest override) once gravatar-android builds its container lazily or exposes a + * public initialize(context) entry point. + */ +object GravatarQuickEditorInitializer { + private const val INITIALIZER_CLASS = "com.gravatar.quickeditor.initializer.QuickEditorContainerInitializer" + + /** + * Runs the library initializer, returning false (after logging) if it could not be run. Callers must not + * open the editor in that case, since it would throw on its uninitialized container. + */ + @Suppress("UNCHECKED_CAST", "TooGenericExceptionCaught") + fun initialize(context: Context): Boolean = try { + val initializer = Class.forName(INITIALIZER_CLASS) as Class> + AppInitializer.getInstance(context).initializeComponent(initializer) + true + } catch (e: Exception) { + AppLog.e(T.MAIN, "Failed to initialize the Gravatar quick editor", e) + false + } catch (e: LinkageError) { + // e.g. NoClassDefFoundError if a library bump moves the class; an Error, so not covered above + AppLog.e(T.MAIN, "Failed to initialize the Gravatar quick editor", e) + false + } +} diff --git a/WordPress/src/main/java/org/wordpress/android/workers/notification/local/LocalNotificationScheduler.kt b/WordPress/src/main/java/org/wordpress/android/workers/notification/local/LocalNotificationScheduler.kt index c9aa4809f56c..dd0df2fe681c 100644 --- a/WordPress/src/main/java/org/wordpress/android/workers/notification/local/LocalNotificationScheduler.kt +++ b/WordPress/src/main/java/org/wordpress/android/workers/notification/local/LocalNotificationScheduler.kt @@ -6,9 +6,12 @@ import androidx.work.WorkManager import org.wordpress.android.workers.notification.local.LocalNotification.Type import javax.inject.Inject -class LocalNotificationScheduler(private val workManager: WorkManager) { +class LocalNotificationScheduler(workManagerProvider: () -> WorkManager) { @Inject - constructor(context: Context) : this(WorkManager.getInstance(context)) + constructor(context: Context) : this({ WorkManager.getInstance(context) }) + + // Resolved on first use so that injecting this class doesn't initialize WorkManager on the main thread + private val workManager by lazy(workManagerProvider) fun scheduleOneTimeNotification(vararg localNotifications: LocalNotification) { workManager.enqueue(localNotifications.map { buildOneTimeWorkRequest(it) }) diff --git a/WordPress/src/main/res/values-ar/strings.xml b/WordPress/src/main/res/values-ar/strings.xml index af614e5a3e90..1da5ec36b3f0 100644 --- a/WordPress/src/main/res/values-ar/strings.xml +++ b/WordPress/src/main/res/values-ar/strings.xml @@ -3832,7 +3832,6 @@ Language: ar وسائط جديدة التغيرات المحلية إعدادات المقالة - حدث خطأ اثناء إنشاء قاعدة بيانات التطبيق. حاول إعادة تنصيب التطبيق. المحاذاة الأفقية سلة المهملات مزعج diff --git a/WordPress/src/main/res/values-az/strings.xml b/WordPress/src/main/res/values-az/strings.xml index ff81a2dc3302..c5921b92d53d 100644 --- a/WordPress/src/main/res/values-az/strings.xml +++ b/WordPress/src/main/res/values-az/strings.xml @@ -125,7 +125,6 @@ Language: az Proqram jurnalı Yerli dəyişikliklər WordPress bloqu - Proqram üçün verilənlər bazası yaradılarkən bir xəta baş verdi. Proqramı təkrar qurmağa cəhd edin. Qeydiyyat gərəklidir Brauzerdə bax Yeni kateqoriya əlavə et diff --git a/WordPress/src/main/res/values-bg/strings.xml b/WordPress/src/main/res/values-bg/strings.xml index 90de587b9728..5b33b8b0f758 100644 --- a/WordPress/src/main/res/values-bg/strings.xml +++ b/WordPress/src/main/res/values-bg/strings.xml @@ -817,7 +817,6 @@ Language: bg Локална чернова Нов файл Текст на връзката (по избор) - Възникна грешка при създаване на базата от данни на приложението. Моля преинсталирайте приложението. Предстоящ Възникна грешка при зареждане на тази плубликация. Опреснете Вашите публикации и опитайте отново. Кошче diff --git a/WordPress/src/main/res/values-cs/strings.xml b/WordPress/src/main/res/values-cs/strings.xml index fdb96b0265c0..c8c61016396c 100644 --- a/WordPress/src/main/res/values-cs/strings.xml +++ b/WordPress/src/main/res/values-cs/strings.xml @@ -3862,7 +3862,6 @@ Language: cs_CZ Schválit Zamítnout Přesunout do koše? - Vyskytla se chyba při vytváření databáze aplikace. Zkuste přeinstalovat tuto aplikaci. Místní změny Protokol aplikace Nastavení příspěvku diff --git a/WordPress/src/main/res/values-cy/strings.xml b/WordPress/src/main/res/values-cy/strings.xml index b8a039839452..9aae351d00df 100644 --- a/WordPress/src/main/res/values-cy/strings.xml +++ b/WordPress/src/main/res/values-cy/strings.xml @@ -461,7 +461,6 @@ Language: cy_GB Cyfryngau newydd Newidiadau lleol Blog WordPress - Digwyddodd gwall wrth greu cronfa ddata\'r ap. Ceisiwch ailosod yr ap. Cofnod yr ap Gwiriwch fod URL y blog yn ddilys Rhannu dolen diff --git a/WordPress/src/main/res/values-de/strings.xml b/WordPress/src/main/res/values-de/strings.xml index 82bb710e825c..83ddd43f5296 100644 --- a/WordPress/src/main/res/values-de/strings.xml +++ b/WordPress/src/main/res/values-de/strings.xml @@ -3836,7 +3836,6 @@ Language: de Dieses Schlagwort konnte nicht entfernt werden Dieses Schlagwort konnte nicht hinzugefügt werden Anwendungsprotokoll - Bei der Erstellung der App-Datenbank ist ein Fehler aufgetreten. Versuche die App erneut zu installieren. Die Medien konnten zu diesem Zeitpunkt nicht aktualisiert werden WordPress-Blog Lokale Änderungen diff --git a/WordPress/src/main/res/values-el/strings.xml b/WordPress/src/main/res/values-el/strings.xml index 9040e767ed0a..25ed9687f0b5 100644 --- a/WordPress/src/main/res/values-el/strings.xml +++ b/WordPress/src/main/res/values-el/strings.xml @@ -1023,7 +1023,6 @@ Language: el_GR Αδυναμία δημιουργίας προσωρινού αρχείου για μεταφόρτωση πολυμέσων. Βεβαιωθείτε ότι υπάρχει αρκετός ελεύθερος χώρος στη συσκευή σας. Απαιτείται εξουσιοδότηση Νέο πολυμέσο - Προέκυψε σφάλμα κατά τη δημιουργία της βάσης δεδομένων της εφαρμογής. Δοκιμάστε να την εγκαταστήσετε ξανά. Αρχείο καταγραφής εφαρμογής Αδυναμία προσθήκης αυτής της ετικέτας Αδυναμία αφαίρεσης αυτής της ετικέτας diff --git a/WordPress/src/main/res/values-en-rAU/strings.xml b/WordPress/src/main/res/values-en-rAU/strings.xml index bce05cdf8590..1db3137d2d9e 100644 --- a/WordPress/src/main/res/values-en-rAU/strings.xml +++ b/WordPress/src/main/res/values-en-rAU/strings.xml @@ -1494,7 +1494,6 @@ Language: en_AU New media Local changes WordPress blog - An error occurred while creating the app database. Try reinstalling the app. Application log Remove site No notifications…yet. diff --git a/WordPress/src/main/res/values-en-rCA/strings.xml b/WordPress/src/main/res/values-en-rCA/strings.xml index cbe358608dca..1084daa8847c 100644 --- a/WordPress/src/main/res/values-en-rCA/strings.xml +++ b/WordPress/src/main/res/values-en-rCA/strings.xml @@ -3465,7 +3465,6 @@ Language: en_CA New media Local changes WordPress blog - An error occurred while creating the app database. Try reinstalling the app. Application log Authorization required Trashed diff --git a/WordPress/src/main/res/values-en-rGB/strings.xml b/WordPress/src/main/res/values-en-rGB/strings.xml index b8cc76aa0b32..737eb990436b 100644 --- a/WordPress/src/main/res/values-en-rGB/strings.xml +++ b/WordPress/src/main/res/values-en-rGB/strings.xml @@ -3836,7 +3836,6 @@ Language: en_GB Unable to remove this tag Unable to add this tag Application log - An error occurred while creating the app database. Try reinstalling the app. Media couldn\'t be refreshed at this time WordPress blog Local changes diff --git a/WordPress/src/main/res/values-es-rCL/strings.xml b/WordPress/src/main/res/values-es-rCL/strings.xml index 54eab0f067b1..fd936c3fe2a2 100644 --- a/WordPress/src/main/res/values-es-rCL/strings.xml +++ b/WordPress/src/main/res/values-es-rCL/strings.xml @@ -3373,7 +3373,6 @@ Language: es_CL Cambios locales Blog de WordPress Registro de la aplicación - Hubo un error al crear la base de datos de la app. Por favor, intenta reinstalar la app. Algunos elementos multimedia no pudieron ser borrados. Prueba más tarde. No se puede actualizar Media en este momento Comprueba que la URL del sitio ingresada es válida diff --git a/WordPress/src/main/res/values-es-rCO/strings.xml b/WordPress/src/main/res/values-es-rCO/strings.xml index 63b367e64a64..9f53c0360a6f 100644 --- a/WordPress/src/main/res/values-es-rCO/strings.xml +++ b/WordPress/src/main/res/values-es-rCO/strings.xml @@ -3872,7 +3872,6 @@ Language: es_CO No ha sido posible encontrar el archivo a cargar. ¿Se ha borrado o cambiado de ubicación? Cuadrícula de miniaturas Ocurrió un error al acceder a este plugin - Ha ocurrido un error al crear la base de datos de la aplicación. Por favor, intenta reinstalar la aplicación. Algunos medios no se han podido borrar en este momento. Inténtalo de nuevo más tarde. Ajustes de entrada No se ha podido eliminar esta etiqueta diff --git a/WordPress/src/main/res/values-es-rMX/strings.xml b/WordPress/src/main/res/values-es-rMX/strings.xml index ac0b1ffed2fc..08f07581a6ae 100644 --- a/WordPress/src/main/res/values-es-rMX/strings.xml +++ b/WordPress/src/main/res/values-es-rMX/strings.xml @@ -1950,7 +1950,6 @@ Language: es_MX Rechazar Blog de WordPress Registro de la aplicación - Hubo un error al crear la base de datos de la app. Por favor, intenta reinstalar la app. No se pueden actualizar los medios en este momento Nuevo elemento multimedia Nueva entrada diff --git a/WordPress/src/main/res/values-es-rVE/strings.xml b/WordPress/src/main/res/values-es-rVE/strings.xml index abe6619789d7..badde3989829 100644 --- a/WordPress/src/main/res/values-es-rVE/strings.xml +++ b/WordPress/src/main/res/values-es-rVE/strings.xml @@ -2657,7 +2657,6 @@ Language: es_VE No ha sido posible encontrar el archivo a cargar. ¿Se ha borrado o cambiado de ubicación? Ocurrió un error al acceder a este plugin Cuadrícula de miniaturas - Ha ocurrido un error al crear la base de datos de la aplicación. Por favor, intenta reinstalar la aplicación. Algunos medios no se han podido borrar en este momento. Inténtalo de nuevo más tarde. Ajustes de entrada Compartir enlace diff --git a/WordPress/src/main/res/values-es/strings.xml b/WordPress/src/main/res/values-es/strings.xml index 27c271d771a7..9a9033f66dc3 100644 --- a/WordPress/src/main/res/values-es/strings.xml +++ b/WordPress/src/main/res/values-es/strings.xml @@ -3836,7 +3836,6 @@ Language: es No se ha podido eliminar esta etiqueta No se ha podido añadir esta etiqueta Registro de la aplicación - Ha ocurrido un error al crear la base de datos de la aplicación. Por favor, intenta reinstalar la aplicación. No se pueden actualizar los medios en este momento Blog de WordPress Cambios locales diff --git a/WordPress/src/main/res/values-eu/strings.xml b/WordPress/src/main/res/values-eu/strings.xml index 47772fbc9105..2d72a16b02eb 100644 --- a/WordPress/src/main/res/values-eu/strings.xml +++ b/WordPress/src/main/res/values-eu/strings.xml @@ -470,7 +470,6 @@ Language: eu_ES Ezin izan da media fitxategia igotzeko behin-behineko fitxategia sortu. Ziurtatu zaitez gailuak behar haina toki duela. Bidalketa berria Media berria - Errorea gertatu da aplikazioaren datu-basea sortzean. Saiatu aplikazioa berrinstalatzen. Aplikazioaren loga Mediaren bat ezin izan da orain ezabatu. Saiatu zaitez berriz beranduago. Errore bat gertatu da bidalketa kargatzean. Eguneratu bidalketak eta saiatu berriz. diff --git a/WordPress/src/main/res/values-fr-rCA/strings.xml b/WordPress/src/main/res/values-fr-rCA/strings.xml index a1d813e4d60f..08ece7c24f7e 100644 --- a/WordPress/src/main/res/values-fr-rCA/strings.xml +++ b/WordPress/src/main/res/values-fr-rCA/strings.xml @@ -3808,7 +3808,6 @@ Language: fr Impossible de supprimer cette étiquette Impossible d’ajouter cette étiquette Journal de l\'application - Une erreur s\'est produite lors de la création de la base de données de l\'app. Essayez de réinstaller l\'app. Impossible d’actualiser le contenu multimédia pour l’instant. Blog WordPress Changements locaux diff --git a/WordPress/src/main/res/values-fr/strings.xml b/WordPress/src/main/res/values-fr/strings.xml index a1d813e4d60f..08ece7c24f7e 100644 --- a/WordPress/src/main/res/values-fr/strings.xml +++ b/WordPress/src/main/res/values-fr/strings.xml @@ -3808,7 +3808,6 @@ Language: fr Impossible de supprimer cette étiquette Impossible d’ajouter cette étiquette Journal de l\'application - Une erreur s\'est produite lors de la création de la base de données de l\'app. Essayez de réinstaller l\'app. Impossible d’actualiser le contenu multimédia pour l’instant. Blog WordPress Changements locaux diff --git a/WordPress/src/main/res/values-gd/strings.xml b/WordPress/src/main/res/values-gd/strings.xml index 6dc89d8baeff..2ddb4f5a7c5c 100644 --- a/WordPress/src/main/res/values-gd/strings.xml +++ b/WordPress/src/main/res/values-gd/strings.xml @@ -150,7 +150,6 @@ Language: gd_GB Meadhan ùr Atharraichean ionadail Bloga WordPress - Thachair mearachd fhad ’s a bha sinn a’ cruthachadh stòr-dàta nan aplacaidean. Feuch is stàlaich an aplacaid às ùr. Loga na h-aplacaid Dèan cinnteach gu bheil an URL a chuir thu a-steach dligheach Co-roinn an ceangal diff --git a/WordPress/src/main/res/values-gl/strings.xml b/WordPress/src/main/res/values-gl/strings.xml index c3d6f4b7420b..a20a3f8c6b02 100644 --- a/WordPress/src/main/res/values-gl/strings.xml +++ b/WordPress/src/main/res/values-gl/strings.xml @@ -3526,7 +3526,6 @@ Language: gl_ES Botar ao lixo? Lixo Rexistro da aplicación - Houbo un erro mentres se creaba a base de datos da aplicación. Proba a reinstalar a aplicación. Houbo un erro mentres se cargaba o artigo. Actualiza os artigos e téntao de novo. Non foi posible atopar o ficheiro para cargar. Terá sido eliminado ou movido? Non se poden actualizar os medios neste momento diff --git a/WordPress/src/main/res/values-he/strings.xml b/WordPress/src/main/res/values-he/strings.xml index a443e18b15a0..69acb83a8e62 100644 --- a/WordPress/src/main/res/values-he/strings.xml +++ b/WordPress/src/main/res/values-he/strings.xml @@ -3816,7 +3816,6 @@ Language: he_IL לא ניתן להסיר תגית זו לא ניתן להוסיף תגית זו יומן יישום - אירעה שגיאה בזמן יצירת מסד הנתונים של היישום. נסה להתקין מחדש את היישום. לא ניתן לרענן את פריטי המדיה כעת אתר ב-WordPress שינויים מקומיים diff --git a/WordPress/src/main/res/values-hi/strings.xml b/WordPress/src/main/res/values-hi/strings.xml index 498a1ba57d71..e92c6f0f2bf0 100644 --- a/WordPress/src/main/res/values-hi/strings.xml +++ b/WordPress/src/main/res/values-hi/strings.xml @@ -277,7 +277,6 @@ Language: hi_IN स्थानीय प्रारूप मीडिया अपलोड करने के लिए अस्थायी फ़ाइल नहीं बनाया जा सका. आपके डिवाइस पर पर्याप्त खाली स्थान है सुनिश्चित करें. अपलोड करने के लिए मीडिया फाइल नहीं मिल सका. उसे हटाया या स्थानांतरित किया गया? - एप्लिकेशन बनाते हुए त्रुटि हुई. एप्लिकेशन को फिर से इनस्टॉल करने का प्रयास करें. एप्लीकेशन लॉग ब्लॉग हटाये पोस्ट हटाये? diff --git a/WordPress/src/main/res/values-hr/strings.xml b/WordPress/src/main/res/values-hr/strings.xml index 91e9920c2e4b..891b38369cb2 100644 --- a/WordPress/src/main/res/values-hr/strings.xml +++ b/WordPress/src/main/res/values-hr/strings.xml @@ -534,7 +534,6 @@ Language: hr Nije moguće pronaći medijski zapis za prijenos. Jeli obrisan ili premješten? Nije moguće kreirati privremeni zapis za prijenos medijskog zapisa. Provjerite da ima dovoljno slobodnog mjesta na vašem uređaju. Potrebna autorizacija - Pojavila se greška prilikom kreiranja app baze podataka. Pokušajte ponovno instalirati app. Ukloni web-stranicu Obriši objavu? Obriši stranicu? diff --git a/WordPress/src/main/res/values-id/strings.xml b/WordPress/src/main/res/values-id/strings.xml index 27c39937c7b5..0e952931f060 100644 --- a/WordPress/src/main/res/values-id/strings.xml +++ b/WordPress/src/main/res/values-id/strings.xml @@ -3825,7 +3825,6 @@ Language: id Tidak bisa menghapus tag ini Tidak bisa menambahkan tag ini Log aplikasi - Terjadi gagal ketika membuat basis data app. Coba instal ulang app. Media tidak bisa disegarkan saat ini Blog WordPress Perubahan lokal diff --git a/WordPress/src/main/res/values-is/strings.xml b/WordPress/src/main/res/values-is/strings.xml index 7d98df625e84..b2be46c5284b 100644 --- a/WordPress/src/main/res/values-is/strings.xml +++ b/WordPress/src/main/res/values-is/strings.xml @@ -461,7 +461,6 @@ Language: is Bæta við nýjum flokki Heiti flokks Leyfisveitingar krafist - Villa kom upp við að stofna gagnagrunn smáforrits. Reyndu að setja smáforritið aftur upp. Atburðarskrá forrits Tengingarvilla Í bið diff --git a/WordPress/src/main/res/values-it/strings.xml b/WordPress/src/main/res/values-it/strings.xml index 3941d4ac2839..7b1769f8c278 100644 --- a/WordPress/src/main/res/values-it/strings.xml +++ b/WordPress/src/main/res/values-it/strings.xml @@ -3836,7 +3836,6 @@ Language: it Impossibile rimuovere questo tag Impossibile aggiungere questo tag Registro applicazione - Si è verificato un errore durante la creazione del database delle app. Prova a reinstallare l\'app. Al momento non è stato possibile aggiornare l\'elemento multimediale Blog di WordPress Modifiche locali diff --git a/WordPress/src/main/res/values-ja/strings.xml b/WordPress/src/main/res/values-ja/strings.xml index c0dcc434db1b..5a2e13d49c17 100644 --- a/WordPress/src/main/res/values-ja/strings.xml +++ b/WordPress/src/main/res/values-ja/strings.xml @@ -3814,7 +3814,6 @@ Language: ja_JP このタグを削除できません このタグを追加できません アプリケーションログ - アプリのデータベースを作成する際にエラーが発生しました。アプリをもう一度インストールしてみてください。 メディアファイルを再読み込みできませんでした WordPress ブログ ローカルの変更 diff --git a/WordPress/src/main/res/values-kmr/strings.xml b/WordPress/src/main/res/values-kmr/strings.xml index 225b0ce3868a..386442b7fea1 100644 --- a/WordPress/src/main/res/values-kmr/strings.xml +++ b/WordPress/src/main/res/values-kmr/strings.xml @@ -1890,7 +1890,6 @@ Language: ku_TR Ji bo hilxistinê dosye nehat dîtin. Ew hatiye jêbirin an jî veguheztin? Reşnivîsa cîgehî Kategoriyan hilbijêre - Dema danegeha sepanê dihat afirandin çewtiyek derket. Sepanê ji nû ve saz bike. Medya niha nayên nûkirin Destûrdarkirin pêwîst e Ji bo hilxistina medyayê dosyeya demkî nayê afirandin. Jê bawer be bila di cîhaza te de têra xwe ciyê vala hebe. diff --git a/WordPress/src/main/res/values-ko/strings.xml b/WordPress/src/main/res/values-ko/strings.xml index e0027480035c..e20e89544358 100644 --- a/WordPress/src/main/res/values-ko/strings.xml +++ b/WordPress/src/main/res/values-ko/strings.xml @@ -3827,7 +3827,6 @@ Language: ko_KR 이 태그를 제거할 수 없음 이 태그를 추가할 수 없음 응용 프로그램 로그 - 앱 데이터베이스를 생성하는 동안 에러가 발생했습니다. 앱을 다시 설치하시기 바랍니다. 현재 미디어를 새로 고칠 수 없습니다 WordPress 블로그 로컬 변경 diff --git a/WordPress/src/main/res/values-lv/strings.xml b/WordPress/src/main/res/values-lv/strings.xml index 1292a8d9f3fb..b3e6d4e294c9 100644 --- a/WordPress/src/main/res/values-lv/strings.xml +++ b/WordPress/src/main/res/values-lv/strings.xml @@ -3359,7 +3359,6 @@ Language: lv Vietējās izmaiņas WordPress emuārs Medijus šobrīd nevar atsvaidzināt - Veidojot lietotņu datu bāzi, radās kļūda. Mēģiniet pārinstalēt lietotni. Lietojumprogrammu žurnāls Atlasiet kategorijas Savienojuma kļūda diff --git a/WordPress/src/main/res/values-mk/strings.xml b/WordPress/src/main/res/values-mk/strings.xml index bb2527e836cb..7150b725b3ba 100644 --- a/WordPress/src/main/res/values-mk/strings.xml +++ b/WordPress/src/main/res/values-mk/strings.xml @@ -88,7 +88,6 @@ Language: mk Зачувување на подесувањата WordPress блог Избери категории - Настана грешка при креирање на базата на податоци за апликацијата. Направи преинсталирање на апликацијата. Дневник на апликацијата Измени коментар Одобри diff --git a/WordPress/src/main/res/values-ms/strings.xml b/WordPress/src/main/res/values-ms/strings.xml index 76b9997f23be..d31e15f7e767 100644 --- a/WordPress/src/main/res/values-ms/strings.xml +++ b/WordPress/src/main/res/values-ms/strings.xml @@ -717,7 +717,6 @@ Language: ms Nama kategori Perubahan setempat Blog WordPress - Ralat berlaku semasa mencipta pangkalan data aplikasi. Cuba memasangnya semula. Log aplikasi Kebenaran diperlukan Kiriman baharu diff --git a/WordPress/src/main/res/values-nb/strings.xml b/WordPress/src/main/res/values-nb/strings.xml index 58f4eb2c4cbc..d2ad527e1500 100644 --- a/WordPress/src/main/res/values-nb/strings.xml +++ b/WordPress/src/main/res/values-nb/strings.xml @@ -2076,7 +2076,6 @@ Language: nb_NO Du har ikke tillatelse til å se mediebiblioteket En feil oppstod under innlastning av innlegget. Oppfrisk innleggene dine, og prøv igjen. Media kunne ikke bli oppfrisket for øyeblikket - En feil oppstod under oppretting av app-databasen. Prøv å reinstallere appen. Forhåndsvisningsnetting Klarte ikke å lage en midlertidig fil for medieopplastning. Vennligst sørg for at det er nok ledig lagring på enheten din. Klarte ikke å finne filen som skulle lastes opp. Ble den kanskje slettet eller flyttet? diff --git a/WordPress/src/main/res/values-nl/strings.xml b/WordPress/src/main/res/values-nl/strings.xml index 3aae69621209..f5564ef3a4f0 100644 --- a/WordPress/src/main/res/values-nl/strings.xml +++ b/WordPress/src/main/res/values-nl/strings.xml @@ -3836,7 +3836,6 @@ Language: nl Deze tag kan niet worden verwijderd Deze tag kan niet worden toegevoegd Applicatie log - Er heeft zich een fout voorgedaan bij het aanmaken van de database van de app. Probeer de app opnieuw te installeren. Media konden op dit moment niet worden vernieuwd WordPress blog Lokale wijzigingen diff --git a/WordPress/src/main/res/values-pl/strings.xml b/WordPress/src/main/res/values-pl/strings.xml index 10071b2f20f0..869056cf4697 100644 --- a/WordPress/src/main/res/values-pl/strings.xml +++ b/WordPress/src/main/res/values-pl/strings.xml @@ -3836,7 +3836,6 @@ Language: pl Nie udało się usunąć tagu Nie udało się dodać tagu Dziennik aplikacji - Wystąpił błąd podczas tworzenia bazy danych. Spróbuj przeinstalować aplikacje. Nie można było odświeżyć mediów w tym momencie WordPress blog Zmiany lokalne diff --git a/WordPress/src/main/res/values-pt-rBR/strings.xml b/WordPress/src/main/res/values-pt-rBR/strings.xml index cdb084193cbe..c3ab24584370 100644 --- a/WordPress/src/main/res/values-pt-rBR/strings.xml +++ b/WordPress/src/main/res/values-pt-rBR/strings.xml @@ -3514,7 +3514,6 @@ Language: pt_BR Não foi possível remover a tag Não foi possível adicionar a tag Log do aplicativo - Ocorreu um erro ao criar o banco de dados do aplicativo. Tente reinstalar o aplicativo. Arquivo de mídia não pôde ser atualizado neste momento Blog WordPress Alterações locais diff --git a/WordPress/src/main/res/values-ro/strings.xml b/WordPress/src/main/res/values-ro/strings.xml index 964c999b0ef2..4171917cc63b 100644 --- a/WordPress/src/main/res/values-ro/strings.xml +++ b/WordPress/src/main/res/values-ro/strings.xml @@ -3853,7 +3853,6 @@ Language: ro Media nouă Schimbări locale Blog WordPress - A apărut o eroare în timp ce se creea baza de date a aplicației. Încearcă reinstalarea ei. Setări pagină Ciornă locală Media nu a putut fi reîmprospătată în acest moment diff --git a/WordPress/src/main/res/values-ru/strings.xml b/WordPress/src/main/res/values-ru/strings.xml index f3c0bf002f29..78edb5e20242 100644 --- a/WordPress/src/main/res/values-ru/strings.xml +++ b/WordPress/src/main/res/values-ru/strings.xml @@ -3836,7 +3836,6 @@ Language: ru Не удается удалить эту метку Не удается подписаться на эту метку Лог приложения - Произошла ошибка при создании базы данных приложения- попробуйте его переустановить. В данный момент не удалось обновить медиафайлы. Блог WordPress Локальные изменения diff --git a/WordPress/src/main/res/values-sk/strings.xml b/WordPress/src/main/res/values-sk/strings.xml index e8dc1cf9bc1e..9e408c8b0816 100644 --- a/WordPress/src/main/res/values-sk/strings.xml +++ b/WordPress/src/main/res/values-sk/strings.xml @@ -1266,7 +1266,6 @@ Language: sk Kôš Text odkazu (voliteľný) Miestne zmeny - Počas vytvárania databázy sa vyskytla chyba. Preinštalujte aplikáciu. Nemáte práva na zobrazenie knižnice súborov Nový súbor Počas načítania príspevku sa vyskytla chyba. Obnovte príspevky a skúste znova. diff --git a/WordPress/src/main/res/values-sq/strings.xml b/WordPress/src/main/res/values-sq/strings.xml index 65b45c81c57d..5b44a3833ae7 100644 --- a/WordPress/src/main/res/values-sq/strings.xml +++ b/WordPress/src/main/res/values-sq/strings.xml @@ -3721,7 +3721,6 @@ Language: sq_AL S’arrihet të hiqet kjo etiketë S’arrihet të shtohet kjo etiketë Regjistër aplikacioni - Ndodhi një gabim gjatë krijimit të bazës së të dhënave për aplikacionin. Provoni të riinstaloni aplikacionin. Media s’u rifreskua dot tani Blog WordPress Ndryshime vendore diff --git a/WordPress/src/main/res/values-sr/strings.xml b/WordPress/src/main/res/values-sr/strings.xml index 26be95e63d22..0b4dfa484753 100644 --- a/WordPress/src/main/res/values-sr/strings.xml +++ b/WordPress/src/main/res/values-sr/strings.xml @@ -1685,7 +1685,6 @@ Language: sr_RS Није могуће направити привремену датотеку за отпремање медија. Потврдите да имате довољно слободног простора за складиштење на свом уређају. Погледајте у прегледачу веба Белешка апликације - Дошло је до грешке током прављења базе података апликације. Покушајте поново са инсталацијом апликације. Водоравно поравнање Непожељни коментар Непожељни коментар diff --git a/WordPress/src/main/res/values-sv/strings.xml b/WordPress/src/main/res/values-sv/strings.xml index 8ddd29598fc4..54b6af3e2e6f 100644 --- a/WordPress/src/main/res/values-sv/strings.xml +++ b/WordPress/src/main/res/values-sv/strings.xml @@ -3836,7 +3836,6 @@ Language: sv_SE Kan inte ta bort denna etikett Kan inte lägga till denna etikett Programlogg - Ett fel uppstod vid skapandet av app-databasen. Försök återinstallera appen. Det gick inte att förnya medialistan just nu WordPress-blogg Lokala ändringar diff --git a/WordPress/src/main/res/values-th/strings.xml b/WordPress/src/main/res/values-th/strings.xml index 00dba26bd92f..9777714fa0ff 100644 --- a/WordPress/src/main/res/values-th/strings.xml +++ b/WordPress/src/main/res/values-th/strings.xml @@ -231,7 +231,6 @@ Language: th ใส่ที่อยู่อีเมลที่ใช้งานได้ ไฟล์สื่อใหม่ บล็อกเวิร์ดเพรส - มีความผิดพลาดเกิดขึ้นระหว่างการสร้างฐานข้อมูลแอพ โปรดลองติดตั้งแอพใหม่อีกครั้ง เรื่องใหม่ ดูในเบราว์เซอร์ เพิ่มหมวดหมู่ใหม่ diff --git a/WordPress/src/main/res/values-tr/strings.xml b/WordPress/src/main/res/values-tr/strings.xml index 670a71c0e0a6..524ababd2754 100644 --- a/WordPress/src/main/res/values-tr/strings.xml +++ b/WordPress/src/main/res/values-tr/strings.xml @@ -3836,7 +3836,6 @@ Language: tr Bu etiket kaldırılamıyor Bu etiket eklenemiyor Uygulama günlüğü - Uygulama veri tabanı oluşturulurken sorun çıktı. Uygulamayı yeniden kurmayı deneyin. Ortam dosyaları şu anda yenilenemedi WordPress blog Yerel değişiklikler diff --git a/WordPress/src/main/res/values-vi/strings.xml b/WordPress/src/main/res/values-vi/strings.xml index 2230207f1466..90783a17312d 100644 --- a/WordPress/src/main/res/values-vi/strings.xml +++ b/WordPress/src/main/res/values-vi/strings.xml @@ -2613,7 +2613,6 @@ Language: vi_VN Không duyệt Viết bài Tải lên media - Xảy ra lỗi khi tạo cơ sở dữ liệu ứng dụng. Thử cài đặt lại ứng dụng. Nhật ký ứng dụng Thêm chuyên mục mới Tên chuyên mục diff --git a/WordPress/src/main/res/values-zh-rCN/strings.xml b/WordPress/src/main/res/values-zh-rCN/strings.xml index ad09a193edff..203688beb11a 100644 --- a/WordPress/src/main/res/values-zh-rCN/strings.xml +++ b/WordPress/src/main/res/values-zh-rCN/strings.xml @@ -3829,7 +3829,6 @@ Language: zh_CN 无法删除此标签 无法添加此标签 程序日志 - 创建程序数据库时出错,请重新安装程序. 此时无法刷新媒体 WordPress 博客 本地修改 diff --git a/WordPress/src/main/res/values-zh-rHK/strings.xml b/WordPress/src/main/res/values-zh-rHK/strings.xml index a0087d66eec6..f35d2ff98218 100644 --- a/WordPress/src/main/res/values-zh-rHK/strings.xml +++ b/WordPress/src/main/res/values-zh-rHK/strings.xml @@ -3816,7 +3816,6 @@ Language: zh_TW 無法移除此標籤 無法新增此標籤 應用程式記錄檔 - 建立應用程式資料庫時發生錯誤。請嘗試重新安裝應用程式。 目前無法重新整理媒體 WordPress 網誌 本機變更 diff --git a/WordPress/src/main/res/values-zh-rTW/strings.xml b/WordPress/src/main/res/values-zh-rTW/strings.xml index a0087d66eec6..f35d2ff98218 100644 --- a/WordPress/src/main/res/values-zh-rTW/strings.xml +++ b/WordPress/src/main/res/values-zh-rTW/strings.xml @@ -3816,7 +3816,6 @@ Language: zh_TW 無法移除此標籤 無法新增此標籤 應用程式記錄檔 - 建立應用程式資料庫時發生錯誤。請嘗試重新安裝應用程式。 目前無法重新整理媒體 WordPress 網誌 本機變更 diff --git a/WordPress/src/main/res/values/strings.xml b/WordPress/src/main/res/values/strings.xml index 874cd44734b5..c1b8f8ee58d3 100644 --- a/WordPress/src/main/res/values/strings.xml +++ b/WordPress/src/main/res/values/strings.xml @@ -2351,7 +2351,6 @@ Your action is not allowed Internal server error occurred This post no longer exists - An error occurred while creating the app database. Try reinstalling the app. An error occurred while copying text to clipboard Couldn\'t retrieve site info Couldn\'t save site info diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a238a9246ab2..d48d5106edf1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -28,6 +28,7 @@ androidx-preference = '1.2.1' androidx-recyclerview = '1.3.2' androidx-room = '2.8.4' androidx-security-crypto = '1.1.0' +androidx-startup = '1.2.0' androidx-swiperefreshlayout = '1.2.0' androidx-test-core = '1.7.0' androidx-test-espresso = '3.7.0' @@ -171,6 +172,7 @@ androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "androidx-room" } androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "androidx-room" } androidx-security-crypto = { module = "androidx.security:security-crypto", version.ref = "androidx-security-crypto" } +androidx-startup-runtime = { module = "androidx.startup:startup-runtime", version.ref = "androidx-startup" } androidx-swiperefreshlayout = { group = "androidx.swiperefreshlayout", name = "swiperefreshlayout", version.ref = "androidx-swiperefreshlayout" } androidx-test-core = { module = "androidx.test:core", version.ref = "androidx-test-core" } androidx-test-espresso-accessibility = { group = "androidx.test.espresso", name = "espresso-accessibility", version.ref = "androidx-test-espresso" }