Merge "Moving some tests to robolectric" into ub-launcher3-master
diff --git a/robolectric_tests/Android.mk b/robolectric_tests/Android.mk
index 62915f2..310d43c 100644
--- a/robolectric_tests/Android.mk
+++ b/robolectric_tests/Android.mk
@@ -27,7 +27,7 @@
mockito-robolectric-prebuilt \
truth-prebuilt
LOCAL_JAVA_LIBRARIES := \
- platform-robolectric-3.6.1-prebuilt
+ platform-robolectric-4.3-prebuilt
LOCAL_JAVA_RESOURCE_DIRS := resources config
@@ -54,4 +54,4 @@
LOCAL_ROBOTEST_TIMEOUT := 36000
-include prebuilts/misc/common/robolectric/3.6.1/run_robotests.mk
+include prebuilts/misc/common/robolectric/4.3/run_robotests.mk
diff --git a/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java b/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
index 5b6d94d..f7e05a4 100644
--- a/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
+++ b/robolectric_tests/src/com/android/launcher3/model/BaseModelUpdateTaskTestCase.java
@@ -1,10 +1,13 @@
package com.android.launcher3.model;
+import static com.android.launcher3.shadows.ShadowLooperExecutor.reinitializeStaticExecutors;
+
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import static org.robolectric.util.ReflectionHelpers.setField;
import android.content.ComponentName;
import android.content.Context;
@@ -29,6 +32,7 @@
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.cache.CachingLogic;
import com.android.launcher3.model.BgDataModel.Callbacks;
+import com.android.launcher3.pm.PackageInstallerCompat;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.TestLauncherProvider;
@@ -53,7 +57,7 @@
public class BaseModelUpdateTaskTestCase {
public final HashMap<Class, HashMap<String, Field>> fieldCache = new HashMap<>();
- private TestLauncherProvider mProvider;
+ public TestLauncherProvider provider;
public Context targetContext;
public UserHandle myUser;
@@ -71,9 +75,11 @@
@Before
public void setUp() throws Exception {
ShadowLog.stream = System.out;
+ reinitializeStaticExecutors();
+ setField(PackageInstallerCompat.class, null, "sInstance", null);
- mProvider = Robolectric.setupContentProvider(TestLauncherProvider.class);
- ShadowContentResolver.registerProviderInternal(LauncherProvider.AUTHORITY, mProvider);
+ provider = Robolectric.setupContentProvider(TestLauncherProvider.class);
+ ShadowContentResolver.registerProviderInternal(LauncherProvider.AUTHORITY, provider);
callbacks = mock(Callbacks.class);
appState = mock(LauncherAppState.class);
diff --git a/robolectric_tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java b/robolectric_tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
new file mode 100644
index 0000000..9e4a43c
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.robolectric.Shadows.shadowOf;
+import static org.robolectric.util.ReflectionHelpers.setField;
+
+import android.content.ComponentName;
+import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.content.pm.PackageInstaller.SessionParams;
+import android.net.Uri;
+import android.provider.Settings;
+
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherProvider;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.shadows.LShadowLauncherApps;
+import com.android.launcher3.shadows.LShadowUserManager;
+import com.android.launcher3.shadows.ShadowLooperExecutor;
+import com.android.launcher3.util.Executors;
+import com.android.launcher3.util.LauncherLayoutBuilder;
+import com.android.launcher3.widget.custom.CustomWidgetManager;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+import org.robolectric.annotation.LooperMode;
+import org.robolectric.annotation.LooperMode.Mode;
+import org.robolectric.shadows.ShadowPackageManager;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+/**
+ * Tests for layout parser for remote layout
+ */
+@RunWith(RobolectricTestRunner.class)
+@Config(shadows = {LShadowUserManager.class, LShadowLauncherApps.class, ShadowLooperExecutor.class})
+@LooperMode(Mode.PAUSED)
+public class DefaultLayoutProviderTest extends BaseModelUpdateTaskTestCase {
+
+ private static final String SETTINGS_APP = "com.android.settings";
+ private static final String TEST_PROVIDER_AUTHORITY =
+ DefaultLayoutProviderTest.class.getName().toLowerCase();
+
+ private static final int BITMAP_SIZE = 10;
+ private static final int GRID_SIZE = 4;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ InvariantDeviceProfile.INSTANCE.initializeForTesting(idp);
+ CustomWidgetManager.INSTANCE.initializeForTesting(mock(CustomWidgetManager.class));
+
+ idp.numRows = idp.numColumns = idp.numHotseatIcons = GRID_SIZE;
+ idp.iconBitmapSize = BITMAP_SIZE;
+
+ provider.setAllowLoadDefaultFavorites(true);
+ Settings.Secure.putString(targetContext.getContentResolver(),
+ "launcher3.layout.provider", TEST_PROVIDER_AUTHORITY);
+
+ ShadowPackageManager spm = shadowOf(targetContext.getPackageManager());
+ spm.addProviderIfNotPresent(new ComponentName("com.test", "Dummy")).authority =
+ TEST_PROVIDER_AUTHORITY;
+ spm.addActivityIfNotPresent(new ComponentName(SETTINGS_APP, SETTINGS_APP));
+ }
+
+ @After
+ public void cleanup() {
+ InvariantDeviceProfile.INSTANCE.initializeForTesting(null);
+ CustomWidgetManager.INSTANCE.initializeForTesting(null);
+ }
+
+ @Test
+ public void testCustomProfileLoaded_with_icon_on_hotseat() throws Exception {
+ writeLayoutAndLoad(new LauncherLayoutBuilder().atHotseat(0)
+ .putApp(SETTINGS_APP, SETTINGS_APP));
+
+ // Verify one item in hotseat
+ assertEquals(1, bgDataModel.workspaceItems.size());
+ ItemInfo info = bgDataModel.workspaceItems.get(0);
+ assertEquals(LauncherSettings.Favorites.CONTAINER_HOTSEAT, info.container);
+ assertEquals(LauncherSettings.Favorites.ITEM_TYPE_APPLICATION, info.itemType);
+ }
+
+ @Test
+ public void testCustomProfileLoaded_with_folder() throws Exception {
+ writeLayoutAndLoad(new LauncherLayoutBuilder().atHotseat(0).putFolder(android.R.string.copy)
+ .addApp(SETTINGS_APP, SETTINGS_APP)
+ .addApp(SETTINGS_APP, SETTINGS_APP)
+ .addApp(SETTINGS_APP, SETTINGS_APP)
+ .build());
+
+ // Verify folder
+ assertEquals(1, bgDataModel.workspaceItems.size());
+ ItemInfo info = bgDataModel.workspaceItems.get(0);
+ assertEquals(LauncherSettings.Favorites.ITEM_TYPE_FOLDER, info.itemType);
+ assertEquals(3, ((FolderInfo) info).contents.size());
+ }
+
+ @Test
+ public void testCustomProfileLoaded_with_widget() throws Exception {
+ String pendingAppPkg = "com.test.pending";
+
+ // Add a dummy session info so that the widget exists
+ SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL);
+ params.setAppPackageName(pendingAppPkg);
+
+ PackageInstaller installer = targetContext.getPackageManager().getPackageInstaller();
+ int sessionId = installer.createSession(params);
+ SessionInfo sessionInfo = installer.getSessionInfo(sessionId);
+ setField(sessionInfo, "installerPackageName", "com.test");
+ setField(sessionInfo, "appIcon", BitmapInfo.LOW_RES_ICON);
+
+ writeLayoutAndLoad(new LauncherLayoutBuilder().atWorkspace(0, 1, 0)
+ .putWidget(pendingAppPkg, "DummyWidget", 2, 2));
+
+ // Verify widget
+ assertEquals(1, bgDataModel.appWidgets.size());
+ ItemInfo info = bgDataModel.appWidgets.get(0);
+ assertEquals(LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET, info.itemType);
+ assertEquals(2, info.spanX);
+ assertEquals(2, info.spanY);
+ }
+
+ private void writeLayoutAndLoad(LauncherLayoutBuilder builder) throws Exception {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ builder.build(new OutputStreamWriter(bos));
+
+ Uri layoutUri = LauncherProvider.getLayoutUri(TEST_PROVIDER_AUTHORITY, targetContext);
+ shadowOf(targetContext.getContentResolver()).registerInputStream(layoutUri,
+ new ByteArrayInputStream(bos.toByteArray()));
+
+ LoaderResults results = new LoaderResults(appState, bgDataModel, allAppsList, 0,
+ new WeakReference<>(callbacks));
+ LoaderTask task = new LoaderTask(appState, allAppsList, bgDataModel, results);
+ Executors.MODEL_EXECUTOR.submit(() -> task.loadWorkspace(new ArrayList<>())).get();
+ }
+}
diff --git a/robolectric_tests/src/com/android/launcher3/shadows/LShadowLauncherApps.java b/robolectric_tests/src/com/android/launcher3/shadows/LShadowLauncherApps.java
new file mode 100644
index 0000000..204ec9b
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/shadows/LShadowLauncherApps.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.shadows;
+
+import static org.robolectric.util.ReflectionHelpers.ClassParameter;
+import static org.robolectric.util.ReflectionHelpers.callConstructor;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ShortcutInfo;
+import android.os.Process;
+import android.os.UserHandle;
+import android.util.ArraySet;
+
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.PackageUserKey;
+
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowLauncherApps;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Extension of {@link ShadowLauncherApps} with missing shadow methods
+ */
+@Implements(value = LauncherApps.class)
+public class LShadowLauncherApps extends ShadowLauncherApps {
+
+ public final ArraySet<PackageUserKey> disabledApps = new ArraySet<>();
+ public final ArraySet<ComponentKey> disabledActivities = new ArraySet<>();
+
+ @Implementation
+ @Override
+ protected List<ShortcutInfo> getShortcuts(LauncherApps.ShortcutQuery query, UserHandle user) {
+ try {
+ return super.getShortcuts(query, user);
+ } catch (UnsupportedOperationException e) {
+ return Collections.emptyList();
+ }
+ }
+
+ @Implementation
+ protected boolean isPackageEnabled(String packageName, UserHandle user) {
+ return !disabledApps.contains(new PackageUserKey(packageName, user));
+ }
+
+ @Implementation
+ protected boolean isActivityEnabled(ComponentName component, UserHandle user) {
+ return !disabledActivities.contains(new ComponentKey(component, user));
+ }
+
+ @Implementation
+ protected LauncherActivityInfo resolveActivity(Intent intent, UserHandle user) {
+ ResolveInfo ri = RuntimeEnvironment.application.getPackageManager()
+ .resolveActivity(intent, 0);
+ return getLauncherActivityInfo(ri.activityInfo);
+ }
+
+ public LauncherActivityInfo getLauncherActivityInfo(ActivityInfo activityInfo) {
+ return callConstructor(LauncherActivityInfo.class,
+ ClassParameter.from(Context.class, RuntimeEnvironment.application),
+ ClassParameter.from(ActivityInfo.class, activityInfo),
+ ClassParameter.from(UserHandle.class, Process.myUserHandle()));
+ }
+
+ @Implementation
+ public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user)
+ throws PackageManager.NameNotFoundException {
+ return RuntimeEnvironment.application.getPackageManager()
+ .getApplicationInfo(packageName, flags);
+ }
+}
diff --git a/robolectric_tests/src/com/android/launcher3/shadows/LShadowUserManager.java b/robolectric_tests/src/com/android/launcher3/shadows/LShadowUserManager.java
new file mode 100644
index 0000000..edf8edb
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/shadows/LShadowUserManager.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.shadows;
+
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.SparseBooleanArray;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.shadows.ShadowUserManager;
+
+/**
+ * Extension of {@link ShadowUserManager} with missing shadow methods
+ */
+@Implements(value = UserManager.class)
+public class LShadowUserManager extends ShadowUserManager {
+
+ private final SparseBooleanArray mQuietUsers = new SparseBooleanArray();
+ private final SparseBooleanArray mLockedUsers = new SparseBooleanArray();
+
+ @Implementation
+ protected boolean isQuietModeEnabled(UserHandle userHandle) {
+ return mQuietUsers.get(userHandle.hashCode());
+ }
+
+ public void setQuietModeEnabled(UserHandle userHandle, boolean enabled) {
+ mQuietUsers.put(userHandle.hashCode(), enabled);
+ }
+
+ @Implementation
+ protected boolean isUserUnlocked(UserHandle userHandle) {
+ return !mLockedUsers.get(userHandle.hashCode());
+ }
+
+ public void setUserLocked(UserHandle userHandle, boolean enabled) {
+ mLockedUsers.put(userHandle.hashCode(), enabled);
+ }
+}
diff --git a/robolectric_tests/src/com/android/launcher3/shadows/ShadowLooperExecutor.java b/robolectric_tests/src/com/android/launcher3/shadows/ShadowLooperExecutor.java
new file mode 100644
index 0000000..d56de3c
--- /dev/null
+++ b/robolectric_tests/src/com/android/launcher3/shadows/ShadowLooperExecutor.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.shadows;
+
+import static com.android.launcher3.util.Executors.createAndStartNewLooper;
+
+import static org.robolectric.shadow.api.Shadow.invokeConstructor;
+import static org.robolectric.util.ReflectionHelpers.ClassParameter.from;
+import static org.robolectric.util.ReflectionHelpers.setField;
+
+import android.os.Handler;
+import android.os.Looper;
+
+import com.android.launcher3.util.Executors;
+import com.android.launcher3.util.LooperExecutor;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.RealObject;
+import org.robolectric.util.ReflectionHelpers;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+/**
+ * Shadow for {@link LooperExecutor} to provide reset functionality for static executors.
+ */
+@Implements(value = LooperExecutor.class, isInAndroidSdk = false)
+public class ShadowLooperExecutor {
+
+ // Keep reference to all created Loopers so they can be torn down after test
+ private static Set<LooperExecutor> executors =
+ Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>()));
+
+ @RealObject private LooperExecutor realExecutor;
+
+ @Implementation
+ protected void __constructor__(Looper looper) {
+ invokeConstructor(LooperExecutor.class, realExecutor, from(Looper.class, looper));
+ executors.add(realExecutor);
+ }
+
+ /**
+ * Re-initializes any executor which may have been reset when a test finished
+ */
+ public static void reinitializeStaticExecutors() {
+ for (LooperExecutor executor : new ArrayList<>(executors)) {
+ setField(executor, "mHandler",
+ new Handler(createAndStartNewLooper(executor.getThread().getName())));
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java b/robolectric_tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
similarity index 100%
rename from tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
rename to robolectric_tests/src/com/android/launcher3/util/LauncherLayoutBuilder.java
diff --git a/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java b/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java
index a9c1a7c..7e873e8 100644
--- a/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java
+++ b/robolectric_tests/src/com/android/launcher3/util/TestLauncherProvider.java
@@ -10,6 +10,8 @@
*/
public class TestLauncherProvider extends LauncherProvider {
+ private boolean mAllowLoadDefaultFavorites;
+
@Override
public boolean onCreate() {
return true;
@@ -18,18 +20,26 @@
@Override
protected synchronized void createDbIfNotExists() {
if (mOpenHelper == null) {
- mOpenHelper = new MyDatabaseHelper(getContext());
+ mOpenHelper = new MyDatabaseHelper(getContext(), mAllowLoadDefaultFavorites);
}
}
+ public void setAllowLoadDefaultFavorites(boolean allowLoadDefaultFavorites) {
+ mAllowLoadDefaultFavorites = allowLoadDefaultFavorites;
+ }
+
public SQLiteDatabase getDb() {
createDbIfNotExists();
return mOpenHelper.getWritableDatabase();
}
private static class MyDatabaseHelper extends DatabaseHelper {
- public MyDatabaseHelper(Context context) {
+
+ private final boolean mAllowLoadDefaultFavorites;
+
+ MyDatabaseHelper(Context context, boolean allowLoadDefaultFavorites) {
super(context, null);
+ mAllowLoadDefaultFavorites = allowLoadDefaultFavorites;
initIds();
}
@@ -39,7 +49,11 @@
}
@Override
- protected void onEmptyDbCreated() { }
+ protected void onEmptyDbCreated() {
+ if (mAllowLoadDefaultFavorites) {
+ super.onEmptyDbCreated();
+ }
+ }
@Override
protected void handleOneTimeDataUpgrade(SQLiteDatabase db) { }
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 42927ea..67fe038 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -484,8 +484,6 @@
*/
private AutoInstallsLayout createWorkspaceLoaderFromAppRestriction(AppWidgetHost widgetHost) {
Context ctx = getContext();
- InvariantDeviceProfile grid = LauncherAppState.getIDP(ctx);
-
String authority = Settings.Secure.getString(ctx.getContentResolver(),
"launcher3.layout.provider");
if (TextUtils.isEmpty(authority)) {
@@ -497,13 +495,7 @@
Log.e(TAG, "No provider found for authority " + authority);
return null;
}
- Uri uri = new Uri.Builder().scheme("content").authority(authority).path("launcher_layout")
- .appendQueryParameter("version", "1")
- .appendQueryParameter("gridWidth", Integer.toString(grid.numColumns))
- .appendQueryParameter("gridHeight", Integer.toString(grid.numRows))
- .appendQueryParameter("hotseatSize", Integer.toString(grid.numHotseatIcons))
- .build();
-
+ Uri uri = getLayoutUri(authority, ctx);
try (InputStream in = ctx.getContentResolver().openInputStream(uri)) {
// Read the full xml so that we fail early in case of any IO error.
String layout = new String(IOUtils.toByteArray(in));
@@ -520,6 +512,16 @@
}
}
+ public static Uri getLayoutUri(String authority, Context ctx) {
+ InvariantDeviceProfile grid = LauncherAppState.getIDP(ctx);
+ return new Uri.Builder().scheme("content").authority(authority).path("launcher_layout")
+ .appendQueryParameter("version", "1")
+ .appendQueryParameter("gridWidth", Integer.toString(grid.numColumns))
+ .appendQueryParameter("gridHeight", Integer.toString(grid.numRows))
+ .appendQueryParameter("hotseatSize", Integer.toString(grid.numHotseatIcons))
+ .build();
+ }
+
private DefaultLayoutParser getDefaultLayoutParser(AppWidgetHost widgetHost) {
InvariantDeviceProfile idp = LauncherAppState.getIDP(getContext());
int defaultLayout = idp.defaultLayoutId;
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 3a4085c..2754cfc 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -42,6 +42,8 @@
import android.util.MutableInt;
import android.util.TimingLogger;
+import androidx.annotation.VisibleForTesting;
+
import com.android.launcher3.AppInfo;
import com.android.launcher3.FolderInfo;
import com.android.launcher3.InstallShortcutReceiver;
@@ -271,7 +273,8 @@
this.notify();
}
- private void loadWorkspace(List<ShortcutInfo> allDeepShortcuts) {
+ @VisibleForTesting
+ void loadWorkspace(List<ShortcutInfo> allDeepShortcuts) {
final Context context = mApp.getContext();
final ContentResolver contentResolver = context.getContentResolver();
final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
diff --git a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java b/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java
deleted file mode 100644
index 1d89d6e..0000000
--- a/tests/src/com/android/launcher3/ui/DefaultLayoutProviderTest.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/**
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.android.launcher3.ui;
-
-import static org.junit.Assert.assertTrue;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.pm.ProviderInfo;
-import android.net.Uri;
-import android.os.ParcelFileDescriptor;
-import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.testcomponent.TestCommandProvider;
-import com.android.launcher3.util.LauncherLayoutBuilder;
-import com.android.launcher3.util.rule.ShellCommandRule;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.OutputStreamWriter;
-
-@MediumTest
-@RunWith(AndroidJUnit4.class)
-public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
-
- @Rule
- public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
-
- private static final String SETTINGS_APP = "com.android.settings";
-
- private Context mContext;
- private String mAuthority;
-
- @Before
- @Override
- public void setUp() throws Exception {
- super.setUp();
-
- mContext = InstrumentationRegistry.getContext();
-
- PackageManager pm = mTargetContext.getPackageManager();
- ProviderInfo pi = pm.getProviderInfo(new ComponentName(mContext,
- TestCommandProvider.class), 0);
- mAuthority = pi.authority;
- }
-
- @Test
- public void testCustomProfileLoaded_with_icon_on_hotseat() throws Exception {
- writeLayout(new LauncherLayoutBuilder().atHotseat(0).putApp(SETTINGS_APP, SETTINGS_APP));
-
- // Launch the home activity
- mDevice.pressHome();
-
- mLauncher.getWorkspace().getHotseatAppIcon(getSettingsApp().getLabel().toString());
- }
-
- @Test
- public void testCustomProfileLoaded_with_widget() throws Exception {
- // A non-restored widget with no config screen gets restored automatically.
- LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(this, false);
-
- writeLayout(new LauncherLayoutBuilder().atWorkspace(0, 1, 0)
- .putWidget(info.getComponent().getPackageName(),
- info.getComponent().getClassName(), 2, 2));
-
- // Launch the home activity
- mDevice.pressHome();
-
- // Verify widget present
- assertTrue("Widget is not present",
- mLauncher.getWorkspace().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null);
- }
-
- @Test
- public void testCustomProfileLoaded_with_folder() throws Exception {
- writeLayout(new LauncherLayoutBuilder().atHotseat(0).putFolder(android.R.string.copy)
- .addApp(SETTINGS_APP, SETTINGS_APP)
- .addApp(SETTINGS_APP, SETTINGS_APP)
- .addApp(SETTINGS_APP, SETTINGS_APP)
- .build());
-
- // Launch the home activity
- mDevice.pressHome();
-
- mLauncher.getWorkspace().getHotseatFolder("Folder: Copy");
- }
-
- @After
- public void cleanup() throws Exception {
- mDevice.executeShellCommand("settings delete secure launcher3.layout.provider");
- }
-
- private void writeLayout(LauncherLayoutBuilder builder) throws Exception {
- mDevice.executeShellCommand("settings put secure launcher3.layout.provider " + mAuthority);
- ParcelFileDescriptor pfd = mTargetContext.getContentResolver().openFileDescriptor(
- Uri.parse("content://" + mAuthority + "/launcher_layout"), "w");
-
- try (OutputStreamWriter writer = new OutputStreamWriter(new AutoCloseOutputStream(pfd))) {
- builder.build(writer);
- }
- clearLauncherData();
- }
-}