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
This commit is contained in:
@@ -35,9 +35,6 @@ import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
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_APPLICATION
|
||||
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 @@ class DevOptionsUiHelper(c: Context, attr: AttributeSet?) : PreferenceGroup(c, a
|
||||
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 @@ class DevOptionsUiHelper(c: Context, attr: AttributeSet?) : PreferenceGroup(c, a
|
||||
val pluginPermissionApps =
|
||||
pm.getPackagesHoldingPermissions(
|
||||
arrayOf(PLUGIN_PERMISSION),
|
||||
PackageManager.MATCH_DISABLED_COMPONENTS
|
||||
PackageManager.MATCH_DISABLED_COMPONENTS,
|
||||
)
|
||||
.map { it.packageName }
|
||||
|
||||
@@ -274,7 +272,7 @@ class DevOptionsUiHelper(c: Context, attr: AttributeSet?) : PreferenceGroup(c, a
|
||||
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 @@ class DevOptionsUiHelper(c: Context, attr: AttributeSet?) : PreferenceGroup(c, a
|
||||
infoList.forEach {
|
||||
manager.pluginEnabler.setDisabled(
|
||||
it.serviceInfo.componentName,
|
||||
disabledState
|
||||
disabledState,
|
||||
)
|
||||
}
|
||||
manager.notifyChange(Intent(Intent.ACTION_PACKAGE_CHANGED, pluginUri))
|
||||
@@ -387,12 +385,12 @@ class DevOptionsUiHelper(c: Context, attr: AttributeSet?) : PreferenceGroup(c, a
|
||||
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 @@ class DevOptionsUiHelper(c: Context, attr: AttributeSet?) : PreferenceGroup(c, a
|
||||
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 @@ class DevOptionsUiHelper(c: Context, attr: AttributeSet?) : PreferenceGroup(c, a
|
||||
info.providerName.className,
|
||||
info.spanX,
|
||||
info.spanY,
|
||||
userType
|
||||
userType,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -520,7 +521,7 @@ class DevOptionsUiHelper(c: Context, attr: AttributeSet?) : PreferenceGroup(c, a
|
||||
private fun createUriPickerIntent(
|
||||
action: String,
|
||||
executor: Executor,
|
||||
callback: (uri: Uri) -> Unit
|
||||
callback: (uri: Uri) -> Unit,
|
||||
): Intent {
|
||||
val pendingIntent =
|
||||
PendingIntent(
|
||||
@@ -532,7 +533,7 @@ class DevOptionsUiHelper(c: Context, attr: AttributeSet?) : PreferenceGroup(c, a
|
||||
allowlistToken: IBinder?,
|
||||
finishedReceiver: IIntentReceiver?,
|
||||
requiredPermission: String?,
|
||||
options: Bundle?
|
||||
options: Bundle?,
|
||||
) {
|
||||
intent.data?.let { uri -> executor.execute { callback(uri) } }
|
||||
}
|
||||
|
||||
@@ -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 @@ public class LauncherSettings {
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,8 @@ import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
|
||||
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 @@ public class ModelDbController {
|
||||
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 @@ public class ModelDbController {
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.Process;
|
||||
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 @@ public class TestUtil {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user