diff --git a/robolectric_tests/Android.mk b/robolectric_tests/Android.mk index 62915f2552..310d43cba4 100644 --- a/robolectric_tests/Android.mk +++ b/robolectric_tests/Android.mk @@ -27,7 +27,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ 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_INSTRUMENT_SOURCE_DIRS := $(dir $(LOCAL_PATH))../src \ 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 5b6d94d732..f7e05a41dd 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.BitmapInfo; 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 @@ import java.util.function.Supplier; public class BaseModelUpdateTaskTestCase { public final HashMap> fieldCache = new HashMap<>(); - private TestLauncherProvider mProvider; + public TestLauncherProvider provider; public Context targetContext; public UserHandle myUser; @@ -71,9 +75,11 @@ public class BaseModelUpdateTaskTestCase { @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 0000000000..9e4a43c1b6 --- /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 0000000000..204ec9bd17 --- /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 disabledApps = new ArraySet<>(); + public final ArraySet disabledActivities = new ArraySet<>(); + + @Implementation + @Override + protected List 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 0000000000..edf8edbb43 --- /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 0000000000..d56de3c9cb --- /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 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 a9c1a7c9d8..7e873e8fa2 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 @@ import com.android.launcher3.LauncherProvider; */ public class TestLauncherProvider extends LauncherProvider { + private boolean mAllowLoadDefaultFavorites; + @Override public boolean onCreate() { return true; @@ -18,18 +20,26 @@ public class TestLauncherProvider extends LauncherProvider { @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 @@ public class TestLauncherProvider extends LauncherProvider { } @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 42927ea1cf..67fe0384b0 100644 --- a/src/com/android/launcher3/LauncherProvider.java +++ b/src/com/android/launcher3/LauncherProvider.java @@ -484,8 +484,6 @@ public class LauncherProvider extends ContentProvider { */ 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 @@ public class LauncherProvider extends ContentProvider { 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 class LauncherProvider extends ContentProvider { } } + 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 3a4085c89c..2754cfc6b8 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -42,6 +42,8 @@ import android.util.LongSparseArray; 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 @@ public class LoaderTask implements Runnable { this.notify(); } - private void loadWorkspace(List allDeepShortcuts) { + @VisibleForTesting + void loadWorkspace(List 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 1d89d6edcb..0000000000 --- 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(); - } -}