Fixing test flakiness in Launcher initialization
Using same key for blob store and content provider based layouts
Using a single key for layout provider. This ensures that if one
test doesn't cleanup properly, any followup test which relies on
model initialization overrides the key appropriately
Bug: 370080120
Test: Presubmit
Flag: EXEMPT bugfix
Change-Id: Idef0a89a5d1ec89e24aae8a4549fd122634dad2f
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
index 181cba0..417bb74 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
@@ -35,9 +35,6 @@
import android.provider.Settings.Secure
import android.text.Html
import android.util.AttributeSet
-import android.util.Base64
-import android.util.Base64.NO_PADDING
-import android.util.Base64.NO_WRAP
import android.view.inputmethod.EditorInfo
import android.widget.TextView
import android.widget.Toast
@@ -57,9 +54,10 @@
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
-import com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY
import com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL
import com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_TAG
+import com.android.launcher3.LauncherSettings.Settings.LAYOUT_PROVIDER_KEY
+import com.android.launcher3.LauncherSettings.Settings.createBlobProviderKey
import com.android.launcher3.R
import com.android.launcher3.model.data.FolderInfo
import com.android.launcher3.model.data.ItemInfo
@@ -241,7 +239,7 @@
private fun DebugInfo<Boolean>.getBoolValue() =
DeviceConfigHelper.prefs.getBoolean(
this.key,
- DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, this.key, this.valueInCode)
+ DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, this.key, this.valueInCode),
)
private fun DebugInfo<Int>.getIntValueAsString() =
@@ -265,7 +263,7 @@
val pluginPermissionApps =
pm.getPackagesHoldingPermissions(
arrayOf(PLUGIN_PERMISSION),
- PackageManager.MATCH_DISABLED_COMPONENTS
+ PackageManager.MATCH_DISABLED_COMPONENTS,
)
.map { it.packageName }
@@ -274,7 +272,7 @@
pm.queryIntentServices(
Intent(action),
PackageManager.MATCH_DISABLED_COMPONENTS or
- PackageManager.GET_RESOLVED_FILTER
+ PackageManager.GET_RESOLVED_FILTER,
)
.filter { pluginPermissionApps.contains(it.serviceInfo.packageName) }
}
@@ -316,7 +314,7 @@
infoList.forEach {
manager.pluginEnabler.setDisabled(
it.serviceInfo.componentName,
- disabledState
+ disabledState,
)
}
manager.notifyChange(Intent(Intent.ACTION_PACKAGE_CHANGED, pluginUri))
@@ -387,12 +385,12 @@
addOnboardPref(
"All Apps Bounce",
HOME_BOUNCE_SEEN.sharedPrefKey,
- HOME_BOUNCE_COUNT.sharedPrefKey
+ HOME_BOUNCE_COUNT.sharedPrefKey,
)
addOnboardPref(
"Hybrid Hotseat Education",
HOTSEAT_DISCOVERY_TIP_COUNT.sharedPrefKey,
- HOTSEAT_LONGPRESS_TIP_SEEN.sharedPrefKey
+ HOTSEAT_LONGPRESS_TIP_SEEN.sharedPrefKey,
)
addOnboardPref("Taskbar Education", TASKBAR_EDU_TOOLTIP_STEP.sharedPrefKey)
addOnboardPref("Taskbar Search Education", TASKBAR_SEARCH_EDU_SEEN.sharedPrefKey)
@@ -470,13 +468,16 @@
session.allowPublicAccess()
session.commit(ORDERED_BG_EXECUTOR) {
- val key = Base64.encodeToString(digest, NO_WRAP or NO_PADDING)
- Secure.putString(resolver, LAYOUT_DIGEST_KEY, key)
+ Secure.putString(
+ resolver,
+ LAYOUT_PROVIDER_KEY,
+ createBlobProviderKey(digest),
+ )
MODEL_EXECUTOR.submit { model.modelDbController.createEmptyDB() }.get()
MAIN_EXECUTOR.submit { model.forceReload() }.get()
MODEL_EXECUTOR.submit {}.get()
- Secure.putString(resolver, LAYOUT_DIGEST_KEY, null)
+ Secure.putString(resolver, LAYOUT_PROVIDER_KEY, null)
}
}
}
@@ -512,7 +513,7 @@
info.providerName.className,
info.spanX,
info.spanY,
- userType
+ userType,
)
}
}
@@ -520,7 +521,7 @@
private fun createUriPickerIntent(
action: String,
executor: Executor,
- callback: (uri: Uri) -> Unit
+ callback: (uri: Uri) -> Unit,
): Intent {
val pendingIntent =
PendingIntent(
@@ -532,7 +533,7 @@
allowlistToken: IBinder?,
finishedReceiver: IIntentReceiver?,
requiredPermission: String?,
- options: Bundle?
+ options: Bundle?,
) {
intent.data?.let { uri -> executor.execute { callback(uri) } }
}
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 87ac193..1d2d161 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -16,8 +16,12 @@
package com.android.launcher3;
+import static android.util.Base64.NO_PADDING;
+import static android.util.Base64.NO_WRAP;
+
import android.database.sqlite.SQLiteDatabase;
import android.provider.BaseColumns;
+import android.util.Base64;
import androidx.annotation.NonNull;
@@ -354,8 +358,17 @@
* Launcher settings
*/
public static final class Settings {
- public static final String LAYOUT_DIGEST_KEY = "launcher3.layout.provider.blob";
+ public static final String LAYOUT_PROVIDER_KEY = "launcher3.layout.provider";
public static final String LAYOUT_DIGEST_LABEL = "launcher-layout";
public static final String LAYOUT_DIGEST_TAG = "ignore";
+ public static final String BLOB_KEY_PREFIX = "blob://";
+
+ /**
+ * Creates a key to be used for {@link #LAYOUT_PROVIDER_KEY}
+ * @param digest byte[] representing the message digest for the blob handle
+ */
+ public static String createBlobProviderKey(byte[] digest) {
+ return BLOB_KEY_PREFIX + Base64.encodeToString(digest, NO_WRAP | NO_PADDING);
+ }
}
}
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index da1a221..5d66d16 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -25,7 +25,8 @@
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb;
-import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY;
+import static com.android.launcher3.LauncherSettings.Settings.BLOB_KEY_PREFIX;
+import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_PROVIDER_KEY;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_TAG;
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
@@ -548,9 +549,15 @@
private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction(
LauncherWidgetHolder widgetHolder) {
ContentResolver cr = mContext.getContentResolver();
- String blobHandlerDigest = Settings.Secure.getString(cr, LAYOUT_DIGEST_KEY);
- if (!TextUtils.isEmpty(blobHandlerDigest)) {
+ String systemLayoutProvider = Settings.Secure.getString(cr, LAYOUT_PROVIDER_KEY);
+ if (TextUtils.isEmpty(systemLayoutProvider)) {
+ return null;
+ }
+
+ // Try the blob store first
+ if (systemLayoutProvider.startsWith(BLOB_KEY_PREFIX)) {
BlobStoreManager blobManager = mContext.getSystemService(BlobStoreManager.class);
+ String blobHandlerDigest = systemLayoutProvider.substring(BLOB_KEY_PREFIX.length());
try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(
blobManager.openBlob(BlobHandle.createWithSha256(
Base64.decode(blobHandlerDigest, NO_WRAP | NO_PADDING),
@@ -562,25 +569,21 @@
}
}
- String authority = Settings.Secure.getString(cr, "launcher3.layout.provider");
- if (TextUtils.isEmpty(authority)) {
- return null;
- }
-
+ // Try contentProvider based provider
PackageManager pm = mContext.getPackageManager();
- ProviderInfo pi = pm.resolveContentProvider(authority, 0);
+ ProviderInfo pi = pm.resolveContentProvider(systemLayoutProvider, 0);
if (pi == null) {
- Log.e(TAG, "No provider found for authority " + authority);
+ Log.e(TAG, "No provider found for authority " + systemLayoutProvider);
return null;
}
- Uri uri = getLayoutUri(authority, mContext);
+ Uri uri = getLayoutUri(systemLayoutProvider, mContext);
try (InputStream in = cr.openInputStream(uri)) {
- Log.d(TAG, "Loading layout from " + authority);
+ Log.d(TAG, "Loading layout from " + systemLayoutProvider);
Resources res = pm.getResourcesForApplication(pi.applicationInfo);
return getAutoInstallsLayoutFromIS(in, widgetHolder, SourceResources.wrap(res));
} catch (Exception e) {
- Log.e(TAG, "Error getting layout stream from: " + authority , e);
+ Log.e(TAG, "Error getting layout stream from: " + systemLayoutProvider , e);
return null;
}
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java b/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java
index 64035da..ce682f1 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java
@@ -15,14 +15,12 @@
*/
package com.android.launcher3.util;
-import static android.util.Base64.NO_PADDING;
-import static android.util.Base64.NO_WRAP;
-
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
-import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_TAG;
+import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_PROVIDER_KEY;
+import static com.android.launcher3.LauncherSettings.Settings.createBlobProviderKey;
import static org.junit.Assert.assertTrue;
@@ -42,7 +40,6 @@
import android.os.UserHandle;
import android.provider.Settings;
import android.system.OsConstants;
-import android.util.Base64;
import android.util.Log;
import androidx.test.uiautomator.UiDevice;
@@ -169,13 +166,12 @@
session.commit(AsyncTask.THREAD_POOL_EXECUTOR, i -> wait.countDown());
}
- String key = Base64.encodeToString(digest, NO_WRAP | NO_PADDING);
-
grantWriteSecurePermission();
- Settings.Secure.putString(context.getContentResolver(), LAYOUT_DIGEST_KEY, key);
+ Settings.Secure.putString(
+ context.getContentResolver(), LAYOUT_PROVIDER_KEY, createBlobProviderKey(digest));
wait.await();
return () ->
- Settings.Secure.putString(context.getContentResolver(), LAYOUT_DIGEST_KEY, null);
+ Settings.Secure.putString(context.getContentResolver(), LAYOUT_PROVIDER_KEY, null);
}
/**