Loading src/com/android/settings/applications/PictureInPictureSettings.java +88 −25 Original line number Diff line number Diff line Loading @@ -22,14 +22,16 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; import android.support.v7.preference.Preference; import android.support.v7.preference.Preference.OnPreferenceClickListener; import android.support.v7.preference.PreferenceScreen; import android.util.ArrayMap; import android.util.IconDrawableFactory; import android.util.Pair; import android.view.View; import com.android.internal.annotations.VisibleForTesting; Loading @@ -37,9 +39,13 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.notification.EmptyTextSettings; import com.android.settings.wrapper.ActivityInfoWrapper; import com.android.settings.wrapper.UserManagerWrapper; import com.android.settingslib.wrapper.PackageManagerWrapper; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class PictureInPictureSettings extends EmptyTextSettings { Loading @@ -51,8 +57,38 @@ public class PictureInPictureSettings extends EmptyTextSettings { IGNORE_PACKAGE_LIST.add("com.android.systemui"); } /** * Comparator by name, then user id. * {@see PackageItemInfo#DisplayNameComparator} */ static class AppComparator implements Comparator<Pair<ApplicationInfo, Integer>> { private final Collator mCollator = Collator.getInstance(); private final PackageManager mPm; public AppComparator(PackageManager pm) { mPm = pm; } public final int compare(Pair<ApplicationInfo, Integer> a, Pair<ApplicationInfo, Integer> b) { CharSequence sa = a.first.loadLabel(mPm); if (sa == null) sa = a.first.name; CharSequence sb = b.first.loadLabel(mPm); if (sb == null) sb = b.first.name; int nameCmp = mCollator.compare(sa.toString(), sb.toString()); if (nameCmp != 0) { return nameCmp; } else { return a.second - b.second; } } } private Context mContext; private PackageManager mPackageManager; private PackageManagerWrapper mPackageManager; private UserManagerWrapper mUserManager; private IconDrawableFactory mIconDrawableFactory; /** * @return true if the package has any activities that declare that they support Loading Loading @@ -94,12 +130,23 @@ public class PictureInPictureSettings extends EmptyTextSettings { return false; } public PictureInPictureSettings() { // Do nothing } public PictureInPictureSettings(PackageManagerWrapper pm, UserManagerWrapper um) { mPackageManager = pm; mUserManager = um; } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); mContext = getActivity(); mPackageManager = mContext.getPackageManager(); mPackageManager = new PackageManagerWrapper(mContext.getPackageManager()); mUserManager = new UserManagerWrapper(mContext.getSystemService(UserManager.class)); mIconDrawableFactory = IconDrawableFactory.newInstance(mContext); setPreferenceScreen(getPreferenceManager().createPreferenceScreen(mContext)); } Loading @@ -111,33 +158,25 @@ public class PictureInPictureSettings extends EmptyTextSettings { final PreferenceScreen screen = getPreferenceScreen(); screen.removeAll(); // Fetch the set of applications which have at least one activity that declare that they // support picture-in-picture final ArrayMap<String, Boolean> packageToState = new ArrayMap<>(); final ArrayList<ApplicationInfo> pipApps = new ArrayList<>(); final List<PackageInfo> installedPackages = mPackageManager.getInstalledPackagesAsUser( GET_ACTIVITIES, UserHandle.myUserId()); for (PackageInfo packageInfo : installedPackages) { if (checkPackageHasPictureInPictureActivities(packageInfo.packageName, packageInfo.activities)) { final String packageName = packageInfo.applicationInfo.packageName; final boolean state = PictureInPictureDetails.getEnterPipStateForPackage( mContext, packageInfo.applicationInfo.uid, packageName); pipApps.add(packageInfo.applicationInfo); packageToState.put(packageName, state); } } Collections.sort(pipApps, new PackageItemInfo.DisplayNameComparator(mPackageManager)); // Fetch the set of applications for each profile which have at least one activity that // declare that they support picture-in-picture final PackageManager pm = mPackageManager.getPackageManager(); final ArrayList<Pair<ApplicationInfo, Integer>> pipApps = collectPipApps(UserHandle.myUserId()); Collections.sort(pipApps, new AppComparator(pm)); // Rebuild the list of prefs final Context prefContext = getPrefContext(); for (final ApplicationInfo appInfo : pipApps) { for (final Pair<ApplicationInfo, Integer> appData : pipApps) { final ApplicationInfo appInfo = appData.first; final int userId = appData.second; final UserHandle user = UserHandle.of(userId); final String packageName = appInfo.packageName; final CharSequence label = appInfo.loadLabel(mPackageManager); final CharSequence label = appInfo.loadLabel(pm); final Preference pref = new Preference(prefContext); pref.setIcon(appInfo.loadIcon(mPackageManager)); pref.setTitle(label); pref.setIcon(mIconDrawableFactory.getBadgedIcon(appInfo, userId)); pref.setTitle(pm.getUserBadgedLabel(label, user)); pref.setSummary(PictureInPictureDetails.getPreferenceSummary(prefContext, appInfo.uid, packageName)); pref.setOnPreferenceClickListener(new OnPreferenceClickListener() { Loading @@ -163,4 +202,28 @@ public class PictureInPictureSettings extends EmptyTextSettings { public int getMetricsCategory() { return MetricsEvent.SETTINGS_MANAGE_PICTURE_IN_PICTURE; } /** * @return the list of applications for the given user and all their profiles that have * activities which support PiP. */ ArrayList<Pair<ApplicationInfo, Integer>> collectPipApps(int userId) { final ArrayList<Pair<ApplicationInfo, Integer>> pipApps = new ArrayList<>(); final ArrayList<Integer> userIds = new ArrayList<>(); for (UserInfo user : mUserManager.getProfiles(userId)) { userIds.add(user.id); } for (int id : userIds) { final List<PackageInfo> installedPackages = mPackageManager.getInstalledPackagesAsUser( GET_ACTIVITIES, id); for (PackageInfo packageInfo : installedPackages) { if (checkPackageHasPictureInPictureActivities(packageInfo.packageName, packageInfo.activities)) { pipApps.add(new Pair<>(packageInfo.applicationInfo, id)); } } } return pipApps; } } src/com/android/settings/wrapper/UserManagerWrapper.java +4 −0 Original line number Diff line number Diff line Loading @@ -41,4 +41,8 @@ public class UserManagerWrapper { public List<UserInfo> getUsers() { return mUserManager.getUsers(); } public List<UserInfo> getProfiles(int userHandle) { return mUserManager.getProfiles(userHandle); } } tests/robotests/src/com/android/settings/applications/PictureInPictureSettingsTest.java 0 → 100644 +170 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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.settings.applications; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.UserInfo; import android.util.Pair; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.TestConfig; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.wrapper.UserManagerWrapper; import com.android.settingslib.wrapper.PackageManagerWrapper; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.Collections; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class PictureInPictureSettingsTest { private static final int PRIMARY_USER_ID = 0; private static final int PROFILE_USER_ID = 10; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; private FakeFeatureFactory mFeatureFactory; private PictureInPictureSettings mFragment; @Mock private PackageManagerWrapper mPackageManager; @Mock private UserManagerWrapper mUserManager; private ArrayList<PackageInfo> mPrimaryUserPackages; private ArrayList<PackageInfo> mProfileUserPackages; private ArrayList<UserInfo> mUsers; @Before public void setUp() { MockitoAnnotations.initMocks(this); FakeFeatureFactory.setupForTest(mContext); mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext); mFragment = new PictureInPictureSettings(mPackageManager, mUserManager); mPrimaryUserPackages = new ArrayList<>(); mProfileUserPackages = new ArrayList<>(); mUsers = new ArrayList<>(); when(mPackageManager.getInstalledPackagesAsUser(anyInt(), eq(PRIMARY_USER_ID))) .thenReturn(mPrimaryUserPackages); when(mPackageManager.getInstalledPackagesAsUser(anyInt(), eq(PROFILE_USER_ID))) .thenReturn(mProfileUserPackages); when(mUserManager.getProfiles(anyInt())).thenReturn(mUsers); } @Test public void testCollectPipApps() { PackageInfo primaryP1 = createPackage("Calculator", true); PackageInfo primaryP2 = createPackage("Clock", false); PackageInfo profileP1 = createPackage("Calculator", false); PackageInfo profileP2 = createPackage("Clock", true); mPrimaryUserPackages.add(primaryP1); mPrimaryUserPackages.add(primaryP2); mProfileUserPackages.add(profileP1); mProfileUserPackages.add(profileP2); ArrayList<Pair<ApplicationInfo, Integer>> apps = mFragment.collectPipApps(PRIMARY_USER_ID); assertThat(containsPackages(apps, primaryP1, profileP2)); assertThat(!containsPackages(apps, primaryP2, profileP1)); } @Test public void testAppSort() { PackageInfo primaryP1 = createPackage("Android", true); PackageInfo primaryP2 = createPackage("Boop", true); PackageInfo primaryP3 = createPackage("Deck", true); PackageInfo profileP1 = createPackage("Android", true); PackageInfo profileP2 = createPackage("Cool", true); PackageInfo profileP3 = createPackage("Fast", false); mPrimaryUserPackages.add(primaryP1); mPrimaryUserPackages.add(primaryP2); mPrimaryUserPackages.add(primaryP3); mProfileUserPackages.add(profileP1); mProfileUserPackages.add(profileP2); mProfileUserPackages.add(profileP3); ArrayList<Pair<ApplicationInfo, Integer>> apps = mFragment.collectPipApps(PRIMARY_USER_ID); Collections.sort(apps, new PictureInPictureSettings.AppComparator(null)); assertThat(isOrdered(apps, primaryP1, profileP1, primaryP2, profileP2)); } private boolean containsPackages(ArrayList<Pair<ApplicationInfo, Integer>> apps, PackageInfo... packages) { for (int i = 0; i < packages.length; i++) { boolean found = false; for (int j = 0; j < apps.size(); j++) { if (apps.get(j).first == packages[i].applicationInfo) { found = true; break; } } if (!found) { return false; } } return true; } private boolean isOrdered(ArrayList<Pair<ApplicationInfo, Integer>> apps, PackageInfo... packages) { if (apps.size() != packages.length) { return false; } for (int i = 0; i < packages.length; i++) { if (packages[i].applicationInfo != apps.get(i).first) { return false; } } return true; } private PackageInfo createPackage(String appTitle, boolean supportsPip) { PackageInfo pi = new PackageInfo(); ActivityInfo ai = new ActivityInfo(); if (supportsPip) { ai.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; } pi.activities = new ActivityInfo[1]; pi.activities[0] = ai; pi.applicationInfo = new ApplicationInfo(); pi.applicationInfo.name = appTitle; return pi; } } Loading
src/com/android/settings/applications/PictureInPictureSettings.java +88 −25 Original line number Diff line number Diff line Loading @@ -22,14 +22,16 @@ import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageItemInfo; import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; import android.support.v7.preference.Preference; import android.support.v7.preference.Preference.OnPreferenceClickListener; import android.support.v7.preference.PreferenceScreen; import android.util.ArrayMap; import android.util.IconDrawableFactory; import android.util.Pair; import android.view.View; import com.android.internal.annotations.VisibleForTesting; Loading @@ -37,9 +39,13 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; import com.android.settings.notification.EmptyTextSettings; import com.android.settings.wrapper.ActivityInfoWrapper; import com.android.settings.wrapper.UserManagerWrapper; import com.android.settingslib.wrapper.PackageManagerWrapper; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class PictureInPictureSettings extends EmptyTextSettings { Loading @@ -51,8 +57,38 @@ public class PictureInPictureSettings extends EmptyTextSettings { IGNORE_PACKAGE_LIST.add("com.android.systemui"); } /** * Comparator by name, then user id. * {@see PackageItemInfo#DisplayNameComparator} */ static class AppComparator implements Comparator<Pair<ApplicationInfo, Integer>> { private final Collator mCollator = Collator.getInstance(); private final PackageManager mPm; public AppComparator(PackageManager pm) { mPm = pm; } public final int compare(Pair<ApplicationInfo, Integer> a, Pair<ApplicationInfo, Integer> b) { CharSequence sa = a.first.loadLabel(mPm); if (sa == null) sa = a.first.name; CharSequence sb = b.first.loadLabel(mPm); if (sb == null) sb = b.first.name; int nameCmp = mCollator.compare(sa.toString(), sb.toString()); if (nameCmp != 0) { return nameCmp; } else { return a.second - b.second; } } } private Context mContext; private PackageManager mPackageManager; private PackageManagerWrapper mPackageManager; private UserManagerWrapper mUserManager; private IconDrawableFactory mIconDrawableFactory; /** * @return true if the package has any activities that declare that they support Loading Loading @@ -94,12 +130,23 @@ public class PictureInPictureSettings extends EmptyTextSettings { return false; } public PictureInPictureSettings() { // Do nothing } public PictureInPictureSettings(PackageManagerWrapper pm, UserManagerWrapper um) { mPackageManager = pm; mUserManager = um; } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); mContext = getActivity(); mPackageManager = mContext.getPackageManager(); mPackageManager = new PackageManagerWrapper(mContext.getPackageManager()); mUserManager = new UserManagerWrapper(mContext.getSystemService(UserManager.class)); mIconDrawableFactory = IconDrawableFactory.newInstance(mContext); setPreferenceScreen(getPreferenceManager().createPreferenceScreen(mContext)); } Loading @@ -111,33 +158,25 @@ public class PictureInPictureSettings extends EmptyTextSettings { final PreferenceScreen screen = getPreferenceScreen(); screen.removeAll(); // Fetch the set of applications which have at least one activity that declare that they // support picture-in-picture final ArrayMap<String, Boolean> packageToState = new ArrayMap<>(); final ArrayList<ApplicationInfo> pipApps = new ArrayList<>(); final List<PackageInfo> installedPackages = mPackageManager.getInstalledPackagesAsUser( GET_ACTIVITIES, UserHandle.myUserId()); for (PackageInfo packageInfo : installedPackages) { if (checkPackageHasPictureInPictureActivities(packageInfo.packageName, packageInfo.activities)) { final String packageName = packageInfo.applicationInfo.packageName; final boolean state = PictureInPictureDetails.getEnterPipStateForPackage( mContext, packageInfo.applicationInfo.uid, packageName); pipApps.add(packageInfo.applicationInfo); packageToState.put(packageName, state); } } Collections.sort(pipApps, new PackageItemInfo.DisplayNameComparator(mPackageManager)); // Fetch the set of applications for each profile which have at least one activity that // declare that they support picture-in-picture final PackageManager pm = mPackageManager.getPackageManager(); final ArrayList<Pair<ApplicationInfo, Integer>> pipApps = collectPipApps(UserHandle.myUserId()); Collections.sort(pipApps, new AppComparator(pm)); // Rebuild the list of prefs final Context prefContext = getPrefContext(); for (final ApplicationInfo appInfo : pipApps) { for (final Pair<ApplicationInfo, Integer> appData : pipApps) { final ApplicationInfo appInfo = appData.first; final int userId = appData.second; final UserHandle user = UserHandle.of(userId); final String packageName = appInfo.packageName; final CharSequence label = appInfo.loadLabel(mPackageManager); final CharSequence label = appInfo.loadLabel(pm); final Preference pref = new Preference(prefContext); pref.setIcon(appInfo.loadIcon(mPackageManager)); pref.setTitle(label); pref.setIcon(mIconDrawableFactory.getBadgedIcon(appInfo, userId)); pref.setTitle(pm.getUserBadgedLabel(label, user)); pref.setSummary(PictureInPictureDetails.getPreferenceSummary(prefContext, appInfo.uid, packageName)); pref.setOnPreferenceClickListener(new OnPreferenceClickListener() { Loading @@ -163,4 +202,28 @@ public class PictureInPictureSettings extends EmptyTextSettings { public int getMetricsCategory() { return MetricsEvent.SETTINGS_MANAGE_PICTURE_IN_PICTURE; } /** * @return the list of applications for the given user and all their profiles that have * activities which support PiP. */ ArrayList<Pair<ApplicationInfo, Integer>> collectPipApps(int userId) { final ArrayList<Pair<ApplicationInfo, Integer>> pipApps = new ArrayList<>(); final ArrayList<Integer> userIds = new ArrayList<>(); for (UserInfo user : mUserManager.getProfiles(userId)) { userIds.add(user.id); } for (int id : userIds) { final List<PackageInfo> installedPackages = mPackageManager.getInstalledPackagesAsUser( GET_ACTIVITIES, id); for (PackageInfo packageInfo : installedPackages) { if (checkPackageHasPictureInPictureActivities(packageInfo.packageName, packageInfo.activities)) { pipApps.add(new Pair<>(packageInfo.applicationInfo, id)); } } } return pipApps; } }
src/com/android/settings/wrapper/UserManagerWrapper.java +4 −0 Original line number Diff line number Diff line Loading @@ -41,4 +41,8 @@ public class UserManagerWrapper { public List<UserInfo> getUsers() { return mUserManager.getUsers(); } public List<UserInfo> getProfiles(int userHandle) { return mUserManager.getProfiles(userHandle); } }
tests/robotests/src/com/android/settings/applications/PictureInPictureSettingsTest.java 0 → 100644 +170 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 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.settings.applications; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.UserInfo; import android.util.Pair; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.TestConfig; import com.android.settings.testutils.FakeFeatureFactory; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settings.wrapper.UserManagerWrapper; import com.android.settingslib.wrapper.PackageManagerWrapper; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; import java.util.ArrayList; import java.util.Collections; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class PictureInPictureSettingsTest { private static final int PRIMARY_USER_ID = 0; private static final int PROFILE_USER_ID = 10; @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; private FakeFeatureFactory mFeatureFactory; private PictureInPictureSettings mFragment; @Mock private PackageManagerWrapper mPackageManager; @Mock private UserManagerWrapper mUserManager; private ArrayList<PackageInfo> mPrimaryUserPackages; private ArrayList<PackageInfo> mProfileUserPackages; private ArrayList<UserInfo> mUsers; @Before public void setUp() { MockitoAnnotations.initMocks(this); FakeFeatureFactory.setupForTest(mContext); mFeatureFactory = (FakeFeatureFactory) FakeFeatureFactory.getFactory(mContext); mFragment = new PictureInPictureSettings(mPackageManager, mUserManager); mPrimaryUserPackages = new ArrayList<>(); mProfileUserPackages = new ArrayList<>(); mUsers = new ArrayList<>(); when(mPackageManager.getInstalledPackagesAsUser(anyInt(), eq(PRIMARY_USER_ID))) .thenReturn(mPrimaryUserPackages); when(mPackageManager.getInstalledPackagesAsUser(anyInt(), eq(PROFILE_USER_ID))) .thenReturn(mProfileUserPackages); when(mUserManager.getProfiles(anyInt())).thenReturn(mUsers); } @Test public void testCollectPipApps() { PackageInfo primaryP1 = createPackage("Calculator", true); PackageInfo primaryP2 = createPackage("Clock", false); PackageInfo profileP1 = createPackage("Calculator", false); PackageInfo profileP2 = createPackage("Clock", true); mPrimaryUserPackages.add(primaryP1); mPrimaryUserPackages.add(primaryP2); mProfileUserPackages.add(profileP1); mProfileUserPackages.add(profileP2); ArrayList<Pair<ApplicationInfo, Integer>> apps = mFragment.collectPipApps(PRIMARY_USER_ID); assertThat(containsPackages(apps, primaryP1, profileP2)); assertThat(!containsPackages(apps, primaryP2, profileP1)); } @Test public void testAppSort() { PackageInfo primaryP1 = createPackage("Android", true); PackageInfo primaryP2 = createPackage("Boop", true); PackageInfo primaryP3 = createPackage("Deck", true); PackageInfo profileP1 = createPackage("Android", true); PackageInfo profileP2 = createPackage("Cool", true); PackageInfo profileP3 = createPackage("Fast", false); mPrimaryUserPackages.add(primaryP1); mPrimaryUserPackages.add(primaryP2); mPrimaryUserPackages.add(primaryP3); mProfileUserPackages.add(profileP1); mProfileUserPackages.add(profileP2); mProfileUserPackages.add(profileP3); ArrayList<Pair<ApplicationInfo, Integer>> apps = mFragment.collectPipApps(PRIMARY_USER_ID); Collections.sort(apps, new PictureInPictureSettings.AppComparator(null)); assertThat(isOrdered(apps, primaryP1, profileP1, primaryP2, profileP2)); } private boolean containsPackages(ArrayList<Pair<ApplicationInfo, Integer>> apps, PackageInfo... packages) { for (int i = 0; i < packages.length; i++) { boolean found = false; for (int j = 0; j < apps.size(); j++) { if (apps.get(j).first == packages[i].applicationInfo) { found = true; break; } } if (!found) { return false; } } return true; } private boolean isOrdered(ArrayList<Pair<ApplicationInfo, Integer>> apps, PackageInfo... packages) { if (apps.size() != packages.length) { return false; } for (int i = 0; i < packages.length; i++) { if (packages[i].applicationInfo != apps.get(i).first) { return false; } } return true; } private PackageInfo createPackage(String appTitle, boolean supportsPip) { PackageInfo pi = new PackageInfo(); ActivityInfo ai = new ActivityInfo(); if (supportsPip) { ai.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; } pi.activities = new ActivityInfo[1]; pi.activities[0] = ai; pi.applicationInfo = new ApplicationInfo(); pi.applicationInfo.name = appTitle; return pi; } }