Merge "Add controllers for iinstant app related preferences."

This commit is contained in:
TreeHugger Robot
2017-12-13 00:56:56 +00:00
committed by Android (Google) Code Review
12 changed files with 672 additions and 207 deletions

View File

@@ -132,6 +132,17 @@
</PreferenceCategory>
<!-- App installer info -->
<PreferenceCategory
android:key="app_installer"
android:title="@string/app_install_details_group_title">
<Preference
android:key="app_info_store"
android:title="@string/app_install_details_title" />
</PreferenceCategory>
<Preference
android:key="app_version"
android:selectable="false"

View File

@@ -45,9 +45,6 @@ import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
@@ -64,6 +61,8 @@ import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.applications.appinfo.AppBatteryPreferenceController;
import com.android.settings.applications.appinfo.AppDataUsagePreferenceController;
import com.android.settings.applications.appinfo.AppInstallerInfoPreferenceController;
import com.android.settings.applications.appinfo.AppInstallerPreferenceCategoryController;
import com.android.settings.applications.appinfo.AppMemoryPreferenceController;
import com.android.settings.applications.appinfo.AppNotificationPreferenceController;
import com.android.settings.applications.appinfo.AppOpenByDefaultPreferenceController;
@@ -77,9 +76,10 @@ import com.android.settings.applications.appinfo.DefaultPhoneShortcutPreferenceC
import com.android.settings.applications.appinfo.DefaultSmsShortcutPreferenceController;
import com.android.settings.applications.appinfo.DrawOverlayDetailPreferenceController;
import com.android.settings.applications.appinfo.ExternalSourceDetailPreferenceController;
import com.android.settings.applications.appinfo.InstantAppButtonsPreferenceController;
import com.android.settings.applications.appinfo.InstantAppDomainsPreferenceController;
import com.android.settings.applications.appinfo.PictureInPictureDetailPreferenceController;
import com.android.settings.applications.appinfo.WriteSystemSettingsPreferenceController;
import com.android.settings.applications.instantapps.InstantAppButtonsController;
import com.android.settings.applications.manageapplications.ManageApplications;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.dashboard.DashboardFragment;
@@ -97,9 +97,9 @@ import com.android.settingslib.core.lifecycle.Lifecycle;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* Dashboard fragment to display application information from Settings. This activity presents
@@ -136,10 +136,7 @@ public class AppInfoDashboardFragment extends DashboardFragment
private static final int DLG_DISABLE = DLG_BASE + 2;
private static final int DLG_SPECIAL_DISABLE = DLG_BASE + 3;
private static final String KEY_HEADER = "header_view";
private static final String KEY_INSTANT_APP_BUTTONS = "instant_app_buttons";
private static final String KEY_ACTION_BUTTONS = "action_buttons";
private static final String KEY_INSTANT_APP_SUPPORTED_LINKS =
"instant_app_launch_supported_domain_urls";
public static final String ARG_PACKAGE_NAME = "package";
public static final String ARG_PACKAGE_UID = "uid";
@@ -172,7 +169,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
private boolean mShowUninstalled;
private LayoutPreference mHeader;
private boolean mUpdatedSysApp = false;
private AppDomainsPreference mInstantAppDomainsPreference;
private boolean mDisableAfterUninstall;
private List<Callback> mCallbacks = new ArrayList<>();
@@ -180,7 +176,7 @@ public class AppInfoDashboardFragment extends DashboardFragment
@VisibleForTesting
ActionButtonPreference mActionButtons;
private InstantAppButtonsController mInstantAppButtonsController;
private InstantAppButtonsPreferenceController mInstantAppButtonPreferenceController;
/**
* Callback to invoke when app info has been changed.
@@ -335,8 +331,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
}
setHasOptionsMenu(true);
addDynamicPrefs();
}
@Override
@@ -381,6 +375,10 @@ public class AppInfoDashboardFragment extends DashboardFragment
controllers.add(new AppOpenByDefaultPreferenceController(context, this));
controllers.add(new AppPermissionPreferenceController(context, this, packageName));
controllers.add(new AppVersionPreferenceController(context, this));
controllers.add(new InstantAppDomainsPreferenceController(context, this));
final AppInstallerInfoPreferenceController appInstallerInfoPreferenceController =
new AppInstallerInfoPreferenceController(context, this, packageName);
controllers.add(appInstallerInfoPreferenceController);
for (AbstractPreferenceController controller : controllers) {
mCallbacks.add((Callback) controller);
@@ -388,6 +386,9 @@ public class AppInfoDashboardFragment extends DashboardFragment
// The following are controllers for preferences that don't need to refresh the preference
// state when app state changes.
mInstantAppButtonPreferenceController =
new InstantAppButtonsPreferenceController(context, this, packageName);
controllers.add(mInstantAppButtonPreferenceController);
controllers.add(new AppBatteryPreferenceController(context, this, packageName, lifecycle));
controllers.add(new AppMemoryPreferenceController(context, this, lifecycle));
controllers.add(new DefaultHomeShortcutPreferenceController(context, packageName));
@@ -407,6 +408,9 @@ public class AppInfoDashboardFragment extends DashboardFragment
controllers.add(new PreferenceCategoryController(
context, KEY_ADVANCED_APP_INFO_CATEGORY, advancedAppInfoControllers));
controllers.add(new AppInstallerPreferenceCategoryController(
context, Arrays.asList(appInstallerInfoPreferenceController)));
return controllers;
}
@@ -444,8 +448,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
.styleActionBar(activity)
.bindHeaderButtons();
mInstantAppDomainsPreference =
(AppDomainsPreference) findPreference(KEY_INSTANT_APP_SUPPORTED_LINKS);
}
@Override
@@ -536,24 +538,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
}
}
/**
* Utility method to hide and show specific preferences based on whether the app being displayed
* is an Instant App or an installed app.
*/
@VisibleForTesting
void prepareInstantAppPrefs() {
final boolean isInstant = AppUtils.isInstant(mPackageInfo.applicationInfo);
if (isInstant) {
Set<String> handledDomainSet = Utils.getHandledDomains(mPm, mPackageInfo.packageName);
String[] handledDomains = handledDomainSet.toArray(new String[handledDomainSet.size()]);
mInstantAppDomainsPreference.setTitles(handledDomains);
// Dummy values, unused in the implementation
mInstantAppDomainsPreference.setValues(new int[handledDomains.length]);
} else {
getPreferenceScreen().removePreference(mInstantAppDomainsPreference);
}
}
// Utility method to set application label and icon.
private void setAppLabelAndIcon(PackageInfo pkgInfo) {
final View appSnippet = mHeader.findViewById(R.id.entity_header);
@@ -642,7 +626,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
checkForceStop();
setAppLabelAndIcon(mPackageInfo);
initUninstallButtons();
prepareInstantAppPrefs();
// Update the preference summaries.
Activity context = getActivity();
@@ -676,7 +659,8 @@ public class AppInfoDashboardFragment extends DashboardFragment
return true;
}
protected AlertDialog createDialog(int id, int errorCode) {
@VisibleForTesting
AlertDialog createDialog(int id, int errorCode) {
switch (id) {
case DLG_DISABLE:
return new AlertDialog.Builder(getActivity())
@@ -722,10 +706,7 @@ public class AppInfoDashboardFragment extends DashboardFragment
.setNegativeButton(R.string.dlg_cancel, null)
.create();
}
if (mInstantAppButtonsController != null) {
return mInstantAppButtonsController.createDialog(id);
}
return null;
return mInstantAppButtonPreferenceController.createDialog(id);
}
private void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) {
@@ -870,57 +851,6 @@ public class AppInfoDashboardFragment extends DashboardFragment
|| (mUserManager.isSplitSystemUser() && userCount == 2);
}
private void addDynamicPrefs() {
if (UserManager.get(getContext()).isManagedProfile()) {
return;
}
addAppInstallerInfoPref(getPreferenceScreen());
maybeAddInstantAppButtons();
}
private void addAppInstallerInfoPref(PreferenceScreen screen) {
String installerPackageName =
AppStoreUtil.getInstallerPackageName(getContext(), mPackageName);
final CharSequence installerLabel = Utils.getApplicationLabel(getContext(),
installerPackageName);
if (installerLabel == null) {
return;
}
final int detailsStringId = AppUtils.isInstant(mPackageInfo.applicationInfo)
? R.string.instant_app_details_summary
: R.string.app_install_details_summary;
PreferenceCategory category = new PreferenceCategory(getPrefContext());
category.setTitle(R.string.app_install_details_group_title);
screen.addPreference(category);
Preference pref = new Preference(getPrefContext());
pref.setTitle(R.string.app_install_details_title);
pref.setKey("app_info_store");
pref.setSummary(getString(detailsStringId, installerLabel));
Intent intent =
AppStoreUtil.getAppStoreLink(getContext(), installerPackageName, mPackageName);
if (intent != null) {
pref.setIntent(intent);
} else {
pref.setEnabled(false);
}
category.addPreference(pref);
}
@VisibleForTesting
void maybeAddInstantAppButtons() {
if (AppUtils.isInstant(mPackageInfo.applicationInfo)) {
LayoutPreference buttons = (LayoutPreference) findPreference(KEY_INSTANT_APP_BUTTONS);
mInstantAppButtonsController = mApplicationFeatureProvider
.newInstantAppButtonsController(this,
buttons.findViewById(R.id.instant_app_button_container),
id -> showDialogInner(id, 0))
.setPackageName(mPackageName)
.show();
}
}
private void onPackageRemoved() {
getActivity().finishActivity(SUB_INFO_FRAGMENT);
getActivity().finishAndRemoveTask();
@@ -1041,9 +971,9 @@ public class AppInfoDashboardFragment extends DashboardFragment
mFinishing = true;
}
private void showDialogInner(int id, int moveErrorCode) {
public void showDialogInner(int id, int moveErrorCode) {
DialogFragment newFragment =
AppInfoBase.MyAlertDialogFragment.newInstance(id, moveErrorCode);
MyAlertDialogFragment.newInstance(id, moveErrorCode);
newFragment.setTargetFragment(this, 0);
newFragment.show(getFragmentManager(), "dialog " + id);
}
@@ -1094,8 +1024,8 @@ public class AppInfoDashboardFragment extends DashboardFragment
public static void startAppInfoFragment(Class<?> fragment, int titleRes,
String pkg, int uid, Activity source, int request, int sourceMetricsCategory) {
Bundle args = new Bundle();
args.putString(AppInfoBase.ARG_PACKAGE_NAME, pkg);
args.putInt(AppInfoBase.ARG_PACKAGE_UID, uid);
args.putString(ARG_PACKAGE_NAME, pkg);
args.putInt(ARG_PACKAGE_UID, uid);
Intent intent = Utils.onBuildStartFragmentIntent(source, fragment.getName(),
args, null, titleRes, null, false, sourceMetricsCategory);
@@ -1116,16 +1046,16 @@ public class AppInfoDashboardFragment extends DashboardFragment
public Dialog onCreateDialog(Bundle savedInstanceState) {
int id = getArguments().getInt(ARG_ID);
int errorCode = getArguments().getInt("moveError");
Dialog dialog = ((AppInfoBase) getTargetFragment()).createDialog(id, errorCode);
Dialog dialog = ((AppInfoDashboardFragment) getTargetFragment())
.createDialog(id, errorCode);
if (dialog == null) {
throw new IllegalArgumentException("unknown id " + id);
}
return dialog;
}
public static AppInfoBase.MyAlertDialogFragment newInstance(int id, int errorCode) {
AppInfoBase.MyAlertDialogFragment
dialogFragment = new AppInfoBase.MyAlertDialogFragment();
public static MyAlertDialogFragment newInstance(int id, int errorCode) {
MyAlertDialogFragment dialogFragment = new MyAlertDialogFragment();
Bundle args = new Bundle();
args.putInt(ARG_ID, id);
args.putInt("moveError", errorCode);

View File

@@ -16,11 +16,9 @@
package com.android.settings.applications;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.util.Log;
// This class provides methods that help dealing with app stores.
@@ -43,9 +41,6 @@ public class AppStoreUtil {
} catch (IllegalArgumentException e) {
Log.e(LOG_TAG, "Exception while retrieving the package installer of " + packageName, e);
}
if (installerPackageName == null) {
return null;
}
return installerPackageName;
}

View File

@@ -0,0 +1,69 @@
/*
* 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.appinfo;
import android.content.Context;
import android.content.Intent;
import android.os.UserManager;
import android.support.v7.preference.Preference;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.applications.AppStoreUtil;
import com.android.settingslib.applications.AppUtils;
public class AppInstallerInfoPreferenceController extends AppInfoPreferenceControllerBase {
private static final String KEY_APP_INSTALLER_INFO = "app_info_store";
private final String mPackageName;
private final String mInstallerPackage;
private final CharSequence mInstallerLabel;
public AppInstallerInfoPreferenceController(Context context, AppInfoDashboardFragment parent,
String packageName) {
super(context, parent, KEY_APP_INSTALLER_INFO);
mPackageName = packageName;
mInstallerPackage = AppStoreUtil.getInstallerPackageName(mContext, mPackageName);
mInstallerLabel = Utils.getApplicationLabel(mContext, mInstallerPackage);
}
@Override
public int getAvailabilityStatus() {
if (UserManager.get(mContext).isManagedProfile()) {
return DISABLED_FOR_USER;
}
return mInstallerLabel!= null ? AVAILABLE : DISABLED_FOR_USER;
}
@Override
public void updateState(Preference preference) {
final int detailsStringId = AppUtils.isInstant(mParent.getPackageInfo().applicationInfo)
? R.string.instant_app_details_summary
: R.string.app_install_details_summary;
preference.setSummary(mContext.getString(detailsStringId, mInstallerLabel));
Intent intent = AppStoreUtil.getAppStoreLink(mContext, mInstallerPackage, mPackageName);
if (intent != null) {
preference.setIntent(intent);
} else {
preference.setEnabled(false);
}
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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.appinfo;
import android.content.Context;
import com.android.settings.widget.PreferenceCategoryController;
import com.android.settingslib.core.AbstractPreferenceController;
import java.util.List;
public class AppInstallerPreferenceCategoryController extends PreferenceCategoryController {
private static final String KEY_APP_INSTALLER_INFO_CATEGORY = "app_installer";
public AppInstallerPreferenceCategoryController(Context context,
List<AbstractPreferenceController> childrenControllers) {
super(context, KEY_APP_INSTALLER_INFO_CATEGORY, childrenControllers);
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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.appinfo;
import android.app.AlertDialog;
import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.applications.ApplicationFeatureProvider;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.applications.instantapps.InstantAppButtonsController;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.applications.AppUtils;
public class InstantAppButtonsPreferenceController extends BasePreferenceController {
private static final String KEY_INSTANT_APP_BUTTONS = "instant_app_buttons";
private final AppInfoDashboardFragment mParent;
private final String mPackageName;
private InstantAppButtonsController mInstantAppButtonsController;
public InstantAppButtonsPreferenceController(Context context, AppInfoDashboardFragment parent,
String packageName) {
super(context, KEY_INSTANT_APP_BUTTONS);
mParent = parent;
mPackageName = packageName;
}
@Override
public int getAvailabilityStatus() {
return AppUtils.isInstant(mParent.getPackageInfo().applicationInfo)
? AVAILABLE : DISABLED_FOR_USER;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
LayoutPreference buttons =
(LayoutPreference) screen.findPreference(KEY_INSTANT_APP_BUTTONS);
mInstantAppButtonsController = getApplicationFeatureProvider()
.newInstantAppButtonsController(mParent,
buttons.findViewById(R.id.instant_app_button_container),
id -> mParent.showDialogInner(id, 0))
.setPackageName(mPackageName)
.show();
}
public AlertDialog createDialog(int id) {
return mInstantAppButtonsController.createDialog(id);
}
@VisibleForTesting
ApplicationFeatureProvider getApplicationFeatureProvider() {
return FeatureFactory.getFactory(mContext).getApplicationFeatureProvider(mContext);
}
}

View File

@@ -0,0 +1,60 @@
/*
* 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.appinfo;
import android.content.Context;
import android.content.pm.PackageManager;
import android.support.v7.preference.Preference;
import com.android.settings.Utils;
import com.android.settings.applications.AppDomainsPreference;
import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settingslib.applications.AppUtils;
import java.util.Set;
public class InstantAppDomainsPreferenceController extends AppInfoPreferenceControllerBase {
private static final String KEY_INSTANT_APP_SUPPORTED_LINKS =
"instant_app_launch_supported_domain_urls";
private PackageManager mPackageManager;
public InstantAppDomainsPreferenceController(Context context, AppInfoDashboardFragment parent) {
super(context, parent, KEY_INSTANT_APP_SUPPORTED_LINKS);
mPackageManager = mContext.getPackageManager();
}
@Override
public int getAvailabilityStatus() {
return AppUtils.isInstant(mParent.getPackageInfo().applicationInfo)
? AVAILABLE : DISABLED_FOR_USER;
}
@Override
public void updateState(Preference preference) {
final AppDomainsPreference instantAppDomainsPreference = (AppDomainsPreference) preference;
final Set<String> handledDomainSet =
Utils.getHandledDomains(mPackageManager, mParent.getPackageInfo().packageName);
final String[] handledDomains =
handledDomainSet.toArray(new String[handledDomainSet.size()]);
instantAppDomainsPreference.setTitles(handledDomains);
// Dummy values, unused in the implementation
instantAppDomainsPreference.setValues(new int[handledDomains.length]);
}
}

View File

@@ -21,7 +21,6 @@ import android.app.Fragment;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.view.View;
import android.widget.Button;

View File

@@ -23,13 +23,10 @@ import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AlertDialog;
import android.app.AppOpsManager;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
@@ -37,16 +34,10 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.UserManager;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceScreen;
import android.view.View;
import com.android.settings.R;
import com.android.settings.SettingsActivity;
import com.android.settings.TestConfig;
import com.android.settings.applications.instantapps.InstantAppButtonsController;
import com.android.settings.applications.instantapps.InstantAppButtonsController.ShowDialogDelegate;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.widget.ActionButtonPreferenceTest;
@@ -246,101 +237,6 @@ public final class AppInfoDashboardFragmentTest {
verify(mAppDetail.mActionButtons).setButton2Visible(false);
}
@Test
public void instantApps_buttonControllerHandlesDialog() {
InstantAppButtonsController mockController = mock(InstantAppButtonsController.class);
ReflectionHelpers.setField(
mAppDetail, "mInstantAppButtonsController", mockController);
// Make sure first that button controller is not called for supported dialog id
AlertDialog mockDialog = mock(AlertDialog.class);
when(mockController.createDialog(InstantAppButtonsController.DLG_CLEAR_APP))
.thenReturn(mockDialog);
assertThat(mAppDetail.createDialog(InstantAppButtonsController.DLG_CLEAR_APP, 0))
.isEqualTo(mockDialog);
verify(mockController).createDialog(InstantAppButtonsController.DLG_CLEAR_APP);
}
// A helper class for testing the InstantAppButtonsController - it lets us look up the
// preference associated with a key for instant app buttons and get back a mock
// LayoutPreference (to avoid a null pointer exception).
public static class InstalledAppDetailsWithMockInstantButtons extends InstalledAppDetails {
@Mock
private LayoutPreference mInstantButtons;
public InstalledAppDetailsWithMockInstantButtons() {
super();
MockitoAnnotations.initMocks(this);
}
@Override
public Preference findPreference(CharSequence key) {
if (key == "instant_app_buttons") {
return mInstantButtons;
}
return super.findPreference(key);
}
}
@Test
public void instantApps_instantSpecificButtons() {
// Make this app appear to be instant.
ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
(InstantAppDataProvider) (i -> true));
final PackageInfo packageInfo = mock(PackageInfo.class);
final InstalledAppDetailsWithMockInstantButtons
fragment = new InstalledAppDetailsWithMockInstantButtons();
ReflectionHelpers.setField(fragment, "mPackageInfo", packageInfo);
ReflectionHelpers.setField(fragment, "mApplicationFeatureProvider",
mFeatureFactory.applicationFeatureProvider);
final InstantAppButtonsController buttonsController =
mock(InstantAppButtonsController.class);
when(buttonsController.setPackageName(nullable(String.class)))
.thenReturn(buttonsController);
when(mFeatureFactory.applicationFeatureProvider.newInstantAppButtonsController(
nullable(Fragment.class), nullable(View.class), nullable(ShowDialogDelegate.class)))
.thenReturn(buttonsController);
fragment.maybeAddInstantAppButtons();
verify(buttonsController).setPackageName(nullable(String.class));
verify(buttonsController).show();
}
@Test
public void instantApps_removeCorrectPref() {
PreferenceScreen mockPreferenceScreen = mock(PreferenceScreen.class);
PreferenceManager mockPreferenceManager = mock(PreferenceManager.class);
AppDomainsPreference mockAppDomainsPref = mock(AppDomainsPreference.class);
PackageInfo mockPackageInfo = mock(PackageInfo.class);
PackageManager mockPackageManager = mock(PackageManager.class);
ReflectionHelpers.setField(
mAppDetail, "mInstantAppDomainsPreference", mockAppDomainsPref);
ReflectionHelpers.setField(
mAppDetail, "mPreferenceManager", mockPreferenceManager);
ReflectionHelpers.setField(
mAppDetail, "mPackageInfo", mockPackageInfo);
ReflectionHelpers.setField(
mAppDetail, "mPm", mockPackageManager);
when(mockPreferenceManager.getPreferenceScreen()).thenReturn(mockPreferenceScreen);
ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
(InstantAppDataProvider) (i -> false));
mAppDetail.prepareInstantAppPrefs();
// For the non instant case we remove the app domain pref, and leave the launch pref
verify(mockPreferenceScreen).removePreference(mockAppDomainsPref);
// For the instant app case we remove the launch preff, and leave the app domain pref
ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
(InstantAppDataProvider) (i -> true));
mAppDetail.prepareInstantAppPrefs();
// Will be 1 still due to above call
verify(mockPreferenceScreen, times(1))
.removePreference(mockAppDomainsPref);
}
@Test
public void onActivityResult_uninstalledUpdates_shouldInvalidateOptionsMenu() {
doReturn(true).when(mAppDetail).refreshUi();

View File

@@ -0,0 +1,147 @@
/*
* 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.appinfo;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.UserManager;
import android.support.v7.preference.Preference;
import com.android.settings.TestConfig;
import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class AppInstallerInfoPreferenceControllerTest {
@Mock
private UserManager mUserManager;
@Mock
private PackageManager mPackageManager;
@Mock
private ApplicationInfo mAppInfo;
@Mock
private AppInfoDashboardFragment mFragment;
@Mock
private Preference mPreference;
private Context mContext;
private AppInstallerInfoPreferenceController mController;
@Before
public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
final String installerPackage = "Installer1";
when(mPackageManager.getInstallerPackageName(anyString())).thenReturn(installerPackage);
when(mPackageManager.getApplicationInfo(eq(installerPackage), anyInt()))
.thenReturn(mAppInfo);
mController = new AppInstallerInfoPreferenceController(mContext, mFragment, "Package1");
}
@Test
public void getAvailabilityStatus_managedProfile_shouldReturnDisabled() {
when(mUserManager.isManagedProfile()).thenReturn(true);
assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.DISABLED_FOR_USER);
}
@Test
public void getAvailabilityStatus_noAppLabel_shouldReturnDisabled() {
when(mUserManager.isManagedProfile()).thenReturn(false);
assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.DISABLED_FOR_USER);
}
@Test
public void getAvailabilityStatus_hasAppLabel_shouldReturnAvailable() {
when(mUserManager.isManagedProfile()).thenReturn(false);
when(mAppInfo.loadLabel(mPackageManager)).thenReturn("Label1");
mController = new AppInstallerInfoPreferenceController(mContext, mFragment, "Package1");
assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.AVAILABLE);
}
@Test
public void updateState_shouldSetSummary() {
final PackageInfo packageInfo = mock(PackageInfo.class);
packageInfo.applicationInfo = mAppInfo;
when(mFragment.getPackageInfo()).thenReturn(packageInfo);
mController.updateState(mPreference);
verify(mPreference).setSummary(any());
}
@Test
public void updateState_noAppStoreLink_shouldDisablePreference() {
final PackageInfo packageInfo = mock(PackageInfo.class);
packageInfo.applicationInfo = mAppInfo;
when(mFragment.getPackageInfo()).thenReturn(packageInfo);
when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(null);
mController.updateState(mPreference);
verify(mPreference).setEnabled(false);
}
@Test
public void updateState_hasAppStoreLink_shouldSetPreferenceIntent() {
final PackageInfo packageInfo = mock(PackageInfo.class);
packageInfo.applicationInfo = mAppInfo;
when(mFragment.getPackageInfo()).thenReturn(packageInfo);
final ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.activityInfo = new ActivityInfo();
resolveInfo.activityInfo.packageName = "Pkg1";
resolveInfo.activityInfo.name = "Name1";
when(mPackageManager.resolveActivity(any(), anyInt())).thenReturn(resolveInfo);
mController.updateState(mPreference);
verify(mPreference, never()).setEnabled(false);
verify(mPreference).setIntent(any(Intent.class));
}
}

View File

@@ -0,0 +1,133 @@
/*
* 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.appinfo;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.AlertDialog;
import android.app.Fragment;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.support.v7.preference.PreferenceScreen;
import android.view.View;
import com.android.settings.TestConfig;
import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.applications.LayoutPreference;
import com.android.settings.applications.instantapps.InstantAppButtonsController;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class InstantAppButtonsPreferenceControllerTest {
@Mock
private PackageManager mPackageManager;
@Mock
private ApplicationInfo mAppInfo;
@Mock
private AppInfoDashboardFragment mFragment;
private Context mContext;
private InstantAppButtonsPreferenceController mController;
private FakeFeatureFactory mFeatureFactory;
@Before
public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
mFeatureFactory = FakeFeatureFactory.setupForTest();
mContext = spy(RuntimeEnvironment.application);
final PackageInfo packageInfo = mock(PackageInfo.class);
packageInfo.applicationInfo = mAppInfo;
when(mFragment.getPackageInfo()).thenReturn(packageInfo);
mController =
spy(new InstantAppButtonsPreferenceController(mContext, mFragment, "Package1"));
}
@Test
public void getAvailabilityStatus_notInstantApp_shouldReturnDisabled() {
ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
(InstantAppDataProvider) (i -> false));
assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.DISABLED_FOR_USER);
}
@Test
public void getAvailabilityStatus_isInstantApp_shouldReturnAvailable() {
ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
(InstantAppDataProvider) (i -> true));
assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.AVAILABLE);
}
@Test
public void displayPreference_shouldSetPreferenceTitle() {
final PreferenceScreen screen = mock(PreferenceScreen.class);
final LayoutPreference preference = mock(LayoutPreference.class);
when(screen.findPreference(mController.getPreferenceKey())).thenReturn(preference);
when(mController.getApplicationFeatureProvider())
.thenReturn(mFeatureFactory.applicationFeatureProvider);
final InstantAppButtonsController buttonsController =
mock(InstantAppButtonsController.class);
when(buttonsController.setPackageName(nullable(String.class)))
.thenReturn(buttonsController);
when(mFeatureFactory.applicationFeatureProvider.newInstantAppButtonsController(
nullable(Fragment.class), nullable(View.class),
nullable(InstantAppButtonsController.ShowDialogDelegate.class)))
.thenReturn(buttonsController);
mController.displayPreference(screen);
verify(buttonsController).setPackageName(nullable(String.class));
verify(buttonsController).show();
}
@Test
public void createDialog_shouldReturnDialogFromButtonController() {
final InstantAppButtonsController buttonsController =
mock(InstantAppButtonsController.class);
ReflectionHelpers.setField(
mController, "mInstantAppButtonsController", buttonsController);
final AlertDialog mockDialog = mock(AlertDialog.class);
when(buttonsController.createDialog(InstantAppButtonsController.DLG_CLEAR_APP))
.thenReturn(mockDialog);
assertThat(mController.createDialog(InstantAppButtonsController.DLG_CLEAR_APP))
.isEqualTo(mockDialog);
}
}

View File

@@ -0,0 +1,115 @@
/*
* 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.appinfo;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.ArraySet;
import com.android.settings.TestConfig;
import com.android.settings.applications.AppDomainsPreference;
import com.android.settings.applications.AppInfoDashboardFragment;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.applications.instantapps.InstantAppDataProvider;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
import java.util.List;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public class InstantAppDomainsPreferenceControllerTest {
@Mock
private PackageManager mPackageManager;
@Mock
private ApplicationInfo mAppInfo;
@Mock
private AppInfoDashboardFragment mFragment;
@Mock
private AppDomainsPreference mPreference;
private Context mContext;
private InstantAppDomainsPreferenceController mController;
@Before
public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
final PackageInfo packageInfo = mock(PackageInfo.class);
packageInfo.applicationInfo = mAppInfo;
packageInfo.packageName = "Package1";
when(mFragment.getPackageInfo()).thenReturn(packageInfo);
mController = new InstantAppDomainsPreferenceController(mContext, mFragment);
}
@Test
public void getAvailabilityStatus_notInstantApp_shouldReturnDisabled() {
ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
(InstantAppDataProvider) (i -> false));
assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.DISABLED_FOR_USER);
}
@Test
public void getAvailabilityStatus_isInstantApp_shouldReturnAvailable() {
ReflectionHelpers.setStaticField(AppUtils.class, "sInstantAppDataProvider",
(InstantAppDataProvider) (i -> true));
assertThat(mController.getAvailabilityStatus()).isEqualTo(mController.AVAILABLE);
}
@Test
public void updateState_shouldSetPreferenceTitle() {
final String[] domain = { "Domain1" };
final ArraySet<String> domains = new ArraySet<>();
domains.add(domain[0]);
final List<IntentFilterVerificationInfo> infoList = new ArrayList<>();
final IntentFilterVerificationInfo info =
new IntentFilterVerificationInfo("Package1", domains);
infoList.add(info);
when(mPackageManager.getIntentFilterVerifications("Package1")).thenReturn(infoList);
mController.updateState(mPreference);
verify(mPreference).setTitles(domain);
}
}