diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 78f9351cfbf..178d2252cbe 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1980,8 +1980,9 @@ - + + @@ -2955,6 +2956,8 @@ + diff --git a/res/values/strings.xml b/res/values/strings.xml index b74ad5da244..6cb164a0df2 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -8180,9 +8180,9 @@ Music - Uninstalled for user %s\n + (uninstalled for user %s) - Disabled for user %s\n + (disabled for user %s) diff --git a/res/xml/development_prefs.xml b/res/xml/development_prefs.xml index b8043c9657e..e857a0e159e 100644 --- a/res/xml/development_prefs.xml +++ b/res/xml/development_prefs.xml @@ -76,7 +76,8 @@ + android:dialogTitle="@string/select_webview_provider_dialog_title" + android:fragment="com.android.settings.webview.WebViewAppPicker" /> candidateList = getCandidates(); if (candidateList != null) { @@ -123,6 +128,10 @@ public abstract class DefaultAppPickerFragment extends InstrumentedPreferenceFra if (TextUtils.equals(systemDefaultAppKey, appKey)) { pref.setSummary(R.string.system_app); } + if (!TextUtils.isEmpty(app.getValue().disabledDescription)) { + pref.setEnabled(false); + pref.setSummary(app.getValue().disabledDescription); + } pref.setOnClickListener(this); screen.addPreference(pref); } @@ -146,18 +155,23 @@ public abstract class DefaultAppPickerFragment extends InstrumentedPreferenceFra private void onRadioButtonConfirmed(String selectedKey) { final boolean success = setDefaultAppKey(selectedKey); if (success) { - final PreferenceScreen screen = getPreferenceScreen(); - if (screen != null) { - final int count = screen.getPreferenceCount(); - for (int i = 0; i < count; i++) { - final Preference pref = screen.getPreference(i); - if (pref instanceof RadioButtonPreference) { - final RadioButtonPreference radioPref = (RadioButtonPreference) pref; - final boolean newCheckedState = - TextUtils.equals(pref.getKey(), selectedKey); - if (radioPref.isChecked() != newCheckedState) { - radioPref.setChecked(TextUtils.equals(pref.getKey(), selectedKey)); - } + updateCheckedState(selectedKey); + } + onSelectionPerformed(success); + } + + @VisibleForTesting + public void updateCheckedState(String selectedKey) { + final PreferenceScreen screen = getPreferenceScreen(); + if (screen != null) { + final int count = screen.getPreferenceCount(); + for (int i = 0; i < count; i++) { + final Preference pref = screen.getPreference(i); + if (pref instanceof RadioButtonPreference) { + final RadioButtonPreference radioPref = (RadioButtonPreference) pref; + final boolean newCheckedState = TextUtils.equals(pref.getKey(), selectedKey); + if (radioPref.isChecked() != newCheckedState) { + radioPref.setChecked(TextUtils.equals(pref.getKey(), selectedKey)); } } } @@ -190,6 +204,9 @@ public abstract class DefaultAppPickerFragment extends InstrumentedPreferenceFra protected abstract boolean setDefaultAppKey(String key); + // Called after the user tries to select an item. + protected void onSelectionPerformed(boolean success) {} + protected String getConfirmationMessage(DefaultAppInfo appInfo) { return null; } diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index 6136bbf36a5..f3f0f87ed79 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -120,6 +120,7 @@ import com.android.settings.system.SystemDashboardFragment; import com.android.settings.tts.TextToSpeechSettings; import com.android.settings.users.UserSettings; import com.android.settings.vpn2.VpnSettings; +import com.android.settings.webview.WebViewAppPicker; import com.android.settings.wfd.WifiDisplaySettings; import com.android.settings.wifi.ConfigureWifiSettings; import com.android.settings.wifi.SavedAccessPointsWifiSettings; @@ -246,6 +247,7 @@ public class SettingsGateway { AppAndNotificationDashboardFragment.class.getName(), UserAndAccountDashboardFragment.class.getName(), EnterprisePrivacySettings.class.getName(), + WebViewAppPicker.class.getName(), }; public static final String[] SETTINGS_FOR_RESTRICTED = { diff --git a/src/com/android/settings/webview/WebViewAppListAdapter.java b/src/com/android/settings/webview/WebViewAppListAdapter.java deleted file mode 100644 index 4c36a475ccc..00000000000 --- a/src/com/android/settings/webview/WebViewAppListAdapter.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * 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.webview; - -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.os.RemoteException; -import android.graphics.Color; -import android.support.annotation.VisibleForTesting; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; - -import com.android.settings.applications.AppViewHolder; -import com.android.settings.R; - -import java.util.ArrayList; -import java.util.List; - -/** - * Custom list adapter for Settings to choose WebView package. - * Note: parts of this class are copied from AppPicker.java. - */ -class WebViewAppListAdapter extends ArrayAdapter { - private final LayoutInflater mInflater; - private final String mCurrentWebViewPackageName; - - public WebViewAppListAdapter(Context context, - WebViewUpdateServiceWrapper webviewUpdateServiceWrapper) { - super(context, 0); - mInflater = LayoutInflater.from(context); - - final List packageInfoList = - new ArrayList(); - List pkgs = - webviewUpdateServiceWrapper.getValidWebViewApplicationInfos(getContext()); - for (ApplicationInfo ai : pkgs) { - WebViewApplicationInfo info = new WebViewApplicationInfo(ai, - ai.loadLabel(context.getPackageManager()).toString(), - getDisabledReason(webviewUpdateServiceWrapper, context, ai.packageName)); - packageInfoList.add(info); - } - addAll(packageInfoList); - - PackageInfo currentWebViewPackage = webviewUpdateServiceWrapper.getCurrentWebViewPackage(); - mCurrentWebViewPackageName = - currentWebViewPackage == null ? null : currentWebViewPackage.packageName; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - // A ViewHolder keeps references to children views to avoid unnecessary calls - // to findViewById() on each row. - AppViewHolder holder = AppViewHolder.createOrRecycle(mInflater, convertView); - convertView = holder.rootView; - WebViewApplicationInfo info = getItem(position); - holder.appName.setText(info.label); - if (info.info != null) { - holder.appIcon.setImageDrawable(info.info.loadIcon(getContext().getPackageManager())); - // Allow disable-description to wrap - to be able to show several lines of text in case - // a package is disabled/uninstalled for several users. - holder.summary.setSingleLine(false); - if (!isEnabled(position)) { - holder.summary.setText(info.disabledReason); - } else { - holder.summary.setText(""); - } - } else { - holder.appIcon.setImageDrawable(null); - holder.summary.setText(""); - } - holder.disabled.setVisibility(View.GONE); - // Only allow a package to be chosen if it is enabled and installed for all users. - convertView.setEnabled(isEnabled(position)); - if (info.info.packageName.equals(mCurrentWebViewPackageName)) { - convertView.setBackgroundColor(Color.GRAY); - } else { - convertView.setBackgroundColor(Color.WHITE); - } - return convertView; - } - - @Override - public boolean isEnabled (int position) { - WebViewApplicationInfo info = getItem(position); - return info.disabledReason == null; - } - - @Override - public boolean areAllItemsEnabled() { - int numItems = getCount(); - for (int n = 0; n < numItems; n++) { - if (!isEnabled(n)) return false; - } - return true; - } - - /** - * Returns the reason why a package cannot be used as WebView implementation. - * This is either because of it being disabled, uninstalled, or hidden for any user. - */ - @VisibleForTesting - static String getDisabledReason(WebViewUpdateServiceWrapper webviewUpdateServiceWrapper, - Context context, String packageName) { - StringBuilder disabledReason = new StringBuilder(); - List userPackages = - webviewUpdateServiceWrapper.getPackageInfosAllUsers(context, packageName); - for (UserPackageWrapper userPackage : userPackages) { - if (!userPackage.isInstalledPackage()) { - // Package uninstalled/hidden - disabledReason.append(context.getString( - R.string.webview_uninstalled_for_user, userPackage.getUserInfo().name)); - } else if (!userPackage.isEnabledPackage()) { - // Package disabled - disabledReason.append(context.getString( - R.string.webview_disabled_for_user, userPackage.getUserInfo().name)); - } - } - if (disabledReason.length() == 0) return null; - return disabledReason.toString(); - } -} - diff --git a/src/com/android/settings/webview/WebViewAppPicker.java b/src/com/android/settings/webview/WebViewAppPicker.java index 2417b004bd6..aa229ac05a0 100644 --- a/src/com/android/settings/webview/WebViewAppPicker.java +++ b/src/com/android/settings/webview/WebViewAppPicker.java @@ -16,57 +16,83 @@ package com.android.settings.webview; -import android.app.ListActivity; +import static android.provider.Settings.ACTION_WEBVIEW_SETTINGS; + +import android.app.Activity; +import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.os.RemoteException; import android.support.annotation.VisibleForTesting; -import android.util.Log; -import android.view.View; -import android.webkit.WebViewFactory; -import android.widget.ListView; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.core.instrumentation.Instrumentable; -import com.android.settings.core.instrumentation.VisibilityLoggerMixin; +import com.android.settings.R; +import com.android.settings.applications.defaultapps.DefaultAppInfo; +import com.android.settings.applications.defaultapps.DefaultAppPickerFragment; -public class WebViewAppPicker extends ListActivity implements Instrumentable { - private static final String TAG = WebViewAppPicker.class.getSimpleName(); - private WebViewAppListAdapter mAdapter; +import java.util.ArrayList; +import java.util.List; + +public class WebViewAppPicker extends DefaultAppPickerFragment { private WebViewUpdateServiceWrapper mWebViewUpdateServiceWrapper; - private final VisibilityLoggerMixin mVisibilityLoggerMixin = - new VisibilityLoggerMixin(getMetricsCategory()); - - @Override - protected void onCreate(Bundle icicle) { - super.onCreate(icicle); - + private WebViewUpdateServiceWrapper getWebViewUpdateServiceWrapper() { if (mWebViewUpdateServiceWrapper == null) { setWebViewUpdateServiceWrapper(createDefaultWebViewUpdateServiceWrapper()); } - mAdapter = new WebViewAppListAdapter(this, mWebViewUpdateServiceWrapper); - setListAdapter(mAdapter); - - mVisibilityLoggerMixin.onAttach(this); + return mWebViewUpdateServiceWrapper; } @Override - protected void onListItemClick(ListView l, View v, int position, long id) { - WebViewApplicationInfo app = mAdapter.getItem(position); + public void onAttach(Context context) { + super.onAttach(context); - if (mWebViewUpdateServiceWrapper.setWebViewProvider(app.info.packageName)) { - Intent intent = new Intent(); - intent.setAction(app.info.packageName); - setResult(RESULT_OK, intent); - } else { - mWebViewUpdateServiceWrapper.showInvalidChoiceToast(this); + if (!mUserManager.isAdminUser()) { + getActivity().finish(); } - finish(); } + @Override + protected List getCandidates() { + final List packageInfoList = new ArrayList(); + List pkgs = + getWebViewUpdateServiceWrapper().getValidWebViewApplicationInfos(getContext()); + for (ApplicationInfo ai : pkgs) { + packageInfoList.add(new DefaultAppInfo(ai, + getDisabledReason(getWebViewUpdateServiceWrapper(), + getContext(), ai.packageName))); + } + return packageInfoList; + } + + @Override + protected String getDefaultAppKey() { + PackageInfo currentPackage = getWebViewUpdateServiceWrapper().getCurrentWebViewPackage(); + return currentPackage == null ? null : currentPackage.packageName; + } + + protected boolean setDefaultAppKey(String key) { + boolean success = getWebViewUpdateServiceWrapper().setWebViewProvider(key); + return success; + } + + @Override + protected void onSelectionPerformed(boolean success) { + if (success) { + Activity activity = getActivity(); + Intent intent = activity == null ? null : activity.getIntent(); + if (intent != null && ACTION_WEBVIEW_SETTINGS.equals(intent.getAction())) { + // If this was started through ACTION_WEBVIEW_SETTINGS then return once we have + // chosen a new package. + getActivity().finish(); + } + } else { + getWebViewUpdateServiceWrapper().showInvalidChoiceToast(getActivity()); + updateCandidates(); + } + } + + private WebViewUpdateServiceWrapper createDefaultWebViewUpdateServiceWrapper() { return new WebViewUpdateServiceWrapper(); } @@ -76,20 +102,32 @@ public class WebViewAppPicker extends ListActivity implements Instrumentable { mWebViewUpdateServiceWrapper = wvusWrapper; } - @Override - public void onResume() { - super.onResume(); - mVisibilityLoggerMixin.onResume(); - } - - @Override - public void onPause() { - super.onPause(); - mVisibilityLoggerMixin.onPause(); - } - @Override public int getMetricsCategory() { return MetricsEvent.WEBVIEW_IMPLEMENTATION; } + + /** + * Returns the reason why a package cannot be used as WebView implementation. + * This is either because of it being disabled, uninstalled, or hidden for any user. + */ + @VisibleForTesting + String getDisabledReason(WebViewUpdateServiceWrapper webviewUpdateServiceWrapper, + Context context, String packageName) { + StringBuilder disabledReason = new StringBuilder(); + List userPackages = + webviewUpdateServiceWrapper.getPackageInfosAllUsers(context, packageName); + for (UserPackageWrapper userPackage : userPackages) { + if (!userPackage.isInstalledPackage()) { + // Package uninstalled/hidden + return context.getString( + R.string.webview_uninstalled_for_user, userPackage.getUserInfo().name); + } else if (!userPackage.isEnabledPackage()) { + // Package disabled + return context.getString( + R.string.webview_disabled_for_user, userPackage.getUserInfo().name); + } + } + return null; + } } diff --git a/src/com/android/settings/webview/WebViewAppPreferenceController.java b/src/com/android/settings/webview/WebViewAppPreferenceController.java index cfb358ed85f..3a181fe7ffa 100644 --- a/src/com/android/settings/webview/WebViewAppPreferenceController.java +++ b/src/com/android/settings/webview/WebViewAppPreferenceController.java @@ -14,18 +14,15 @@ package com.android.settings.webview; -import android.app.Activity; -import android.content.pm.PackageInfo; import android.content.Context; -import android.content.Intent; -import android.support.annotation.VisibleForTesting; +import android.content.pm.PackageInfo; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; -import com.android.settings.DevelopmentSettings; -import com.android.settings.core.PreferenceController; +import com.android.settings.applications.defaultapps.DefaultAppInfo; +import com.android.settings.applications.defaultapps.DefaultAppPreferenceController; -public class WebViewAppPreferenceController extends PreferenceController { +public class WebViewAppPreferenceController extends DefaultAppPreferenceController { private static final String WEBVIEW_APP_KEY = "select_webview_provider"; @@ -45,20 +42,9 @@ public class WebViewAppPreferenceController extends PreferenceController { } @Override - public boolean handlePreferenceTreeClick(Preference preference) { - if (getPreferenceKey().equals(preference.getKey())) { - return true; - } - return false; - } - - public Intent getActivityIntent() { - return new Intent(mContext, WebViewAppPicker.class); - } - - @Override - public void updateState(Preference preference) { - mPreference.setSummary(getCurrentWebViewPackageLabel(mContext)); + public DefaultAppInfo getDefaultAppInfo() { + PackageInfo currentPackage = mWebViewUpdateServiceWrapper.getCurrentWebViewPackage(); + return new DefaultAppInfo(currentPackage == null ? null : currentPackage.applicationInfo); } @Override @@ -69,23 +55,6 @@ public class WebViewAppPreferenceController extends PreferenceController { } } - /** - * Handle the return-value from the WebViewAppPicker Activity. - */ - public void onActivityResult(int resultCode, Intent data) { - // Update the preference summary no matter whether we succeeded to change the webview - // implementation correctly - we might have changed implementation to one the user did not - // choose. - updateState(null); - } - - private String getCurrentWebViewPackageLabel(Context context) { - PackageInfo webViewPackage = mWebViewUpdateServiceWrapper.getCurrentWebViewPackage(); - if (webViewPackage == null) return ""; - return webViewPackage.applicationInfo.loadLabel(context.getPackageManager()).toString(); - } - - @Override public String getPreferenceKey() { return WEBVIEW_APP_KEY; diff --git a/src/com/android/settings/webview/WebViewApplicationInfo.java b/src/com/android/settings/webview/WebViewApplicationInfo.java deleted file mode 100644 index 6879c59f48a..00000000000 --- a/src/com/android/settings/webview/WebViewApplicationInfo.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.webview; - -import android.content.pm.ApplicationInfo; - -final class WebViewApplicationInfo { - final ApplicationInfo info; - final String label; - final String disabledReason; - - public WebViewApplicationInfo(ApplicationInfo info, String label, String disabledReason) { - this.info = info; - this.label = label; - this.disabledReason = disabledReason; - } -} diff --git a/tests/robotests/src/com/android/settings/webview/WebViewAppListAdapterTest.java b/tests/robotests/src/com/android/settings/webview/WebViewAppListAdapterTest.java deleted file mode 100644 index a8ab5d46f56..00000000000 --- a/tests/robotests/src/com/android/settings/webview/WebViewAppListAdapterTest.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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.webview; - -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import android.content.Context; -import android.content.pm.UserInfo; - -import com.android.settings.R; -import com.android.settings.SettingsRobolectricTestRunner; -import com.android.settings.TestConfig; - -import java.util.Arrays; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.robolectric.RuntimeEnvironment; -import org.robolectric.annotation.Config; - -@RunWith(SettingsRobolectricTestRunner.class) -@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) -public class WebViewAppListAdapterTest { - private Context mContext = RuntimeEnvironment.application; - - private final static UserInfo FIRST_USER = new UserInfo(0, "FIRST_USER", 0); - private final static UserInfo SECOND_USER = new UserInfo(0, "SECOND_USER", 0); - - private final static String DEFAULT_PACKAGE_NAME = "DEFAULT_PACKAGE_NAME"; - - @Test - public void testDisabledReasonNullIfPackagesOk() { - UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class); - when(packageForFirstUser.isEnabledPackage()).thenReturn(true); - when(packageForFirstUser.isInstalledPackage()).thenReturn(true); - - UserPackageWrapper packageForSecondUser = mock(UserPackageWrapper.class); - when(packageForSecondUser.isEnabledPackage()).thenReturn(true); - when(packageForSecondUser.isInstalledPackage()).thenReturn(true); - - WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); - when(wvusWrapper.getPackageInfosAllUsers( - any(), eq(DEFAULT_PACKAGE_NAME))).thenReturn( - Arrays.asList(packageForFirstUser, packageForSecondUser)); - - assertThat(WebViewAppListAdapter.getDisabledReason( - wvusWrapper, mContext, DEFAULT_PACKAGE_NAME)).isNull(); - } - - @Test - public void testDisabledReasonForSingleUserDisabledPackage() { - UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class); - when(packageForFirstUser.isEnabledPackage()).thenReturn(false); - when(packageForFirstUser.isInstalledPackage()).thenReturn(true); - when(packageForFirstUser.getUserInfo()).thenReturn(FIRST_USER); - - WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); - when(wvusWrapper.getPackageInfosAllUsers(any(), eq(DEFAULT_PACKAGE_NAME) - )).thenReturn(Arrays.asList(packageForFirstUser)); - - assertThat(WebViewAppListAdapter.getDisabledReason(wvusWrapper, mContext, - DEFAULT_PACKAGE_NAME)).isEqualTo("Disabled for user " + FIRST_USER.name + "\n"); - } - - @Test - public void testDisabledReasonForSingleUserUninstalledPackage() { - UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class); - when(packageForFirstUser.isEnabledPackage()).thenReturn(true); - when(packageForFirstUser.isInstalledPackage()).thenReturn(false); - when(packageForFirstUser.getUserInfo()).thenReturn(FIRST_USER); - - WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); - when(wvusWrapper.getPackageInfosAllUsers(any(), eq(DEFAULT_PACKAGE_NAME) - )).thenReturn(Arrays.asList(packageForFirstUser)); - - assertThat(WebViewAppListAdapter.getDisabledReason(wvusWrapper, mContext, - DEFAULT_PACKAGE_NAME)).isEqualTo("Uninstalled for user " + FIRST_USER.name + "\n"); - } - - @Test - public void testDisabledReasonSeveralUsers() { - UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class); - when(packageForFirstUser.isEnabledPackage()).thenReturn(false); - when(packageForFirstUser.isInstalledPackage()).thenReturn(true); - when(packageForFirstUser.getUserInfo()).thenReturn(FIRST_USER); - - UserPackageWrapper packageForSecondUser = mock(UserPackageWrapper.class); - when(packageForSecondUser.isEnabledPackage()).thenReturn(true); - when(packageForSecondUser.isInstalledPackage()).thenReturn(false); - when(packageForSecondUser.getUserInfo()).thenReturn(SECOND_USER); - - WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); - when(wvusWrapper.getPackageInfosAllUsers(any(), eq(DEFAULT_PACKAGE_NAME) - )).thenReturn(Arrays.asList(packageForFirstUser, packageForSecondUser)); - - final String EXPECTED_DISABLED_REASON = String.format( - "Disabled for user %s\nUninstalled for user %s\n", - FIRST_USER.name, SECOND_USER.name); - assertThat(WebViewAppListAdapter.getDisabledReason( - wvusWrapper, mContext,DEFAULT_PACKAGE_NAME)).isEqualTo(EXPECTED_DISABLED_REASON); - } - - /** - * Ensure we only proclaim a package as uninstalled for a certain user if it's both uninstalled - * and disabled. - */ - @Test - public void testDisabledReasonUninstalledAndDisabled() { - UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class); - when(packageForFirstUser.isEnabledPackage()).thenReturn(false); - when(packageForFirstUser.isInstalledPackage()).thenReturn(false); - when(packageForFirstUser.getUserInfo()).thenReturn(FIRST_USER); - - UserPackageWrapper packageForSecondUser = mock(UserPackageWrapper.class); - when(packageForSecondUser.isEnabledPackage()).thenReturn(true); - when(packageForSecondUser.isInstalledPackage()).thenReturn(true); - when(packageForSecondUser.getUserInfo()).thenReturn(SECOND_USER); - - WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); - when(wvusWrapper.getPackageInfosAllUsers(any(), eq(DEFAULT_PACKAGE_NAME) - )).thenReturn(Arrays.asList(packageForFirstUser, packageForSecondUser)); - - final String EXPECTED_DISABLED_REASON = String.format( - "Uninstalled for user %s\n", FIRST_USER.name); - assertThat(WebViewAppListAdapter.getDisabledReason(wvusWrapper, mContext, - DEFAULT_PACKAGE_NAME)).isEqualTo(EXPECTED_DISABLED_REASON); - } -} diff --git a/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java b/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java index 8ace8aadd5a..78839faeef8 100644 --- a/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java +++ b/tests/robotests/src/com/android/settings/webview/WebViewAppPickerTest.java @@ -16,94 +16,252 @@ package com.android.settings.webview; +import static android.provider.Settings.ACTION_WEBVIEW_SETTINGS; import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doNothing; +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 static org.robolectric.shadows.ShadowView.clickOn; -import static org.robolectric.Shadows.shadowOf; import android.app.Activity; +import android.content.Context; +import android.content.Intent; import android.content.pm.ApplicationInfo; -import android.view.View; +import android.content.pm.UserInfo; +import android.os.UserManager; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; +import com.android.settings.widget.RadioButtonPreference; +import com.android.settings.applications.PackageManagerWrapper; import java.util.Arrays; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.Robolectric; +import org.mockito.Answers; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import org.robolectric.util.ActivityController; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class WebViewAppPickerTest { + private Context mContext = RuntimeEnvironment.application; - private static final String DEFAULT_PACKAGE_NAME = "DEFAULT_PACKAGE_NAME"; + private final static UserInfo FIRST_USER = new UserInfo(0, "FIRST_USER", 0); + private final static UserInfo SECOND_USER = new UserInfo(0, "SECOND_USER", 0); - private static ApplicationInfo createApplicationInfo(String packageName) { - ApplicationInfo ai = new ApplicationInfo(); - ai.packageName = packageName; - return ai; - } + private final static String DEFAULT_PACKAGE_NAME = "DEFAULT_PACKAGE_NAME"; - @Test - public void testClickingItemChangesProvider() { - ActivityController controller = - Robolectric.buildActivity(WebViewAppPicker.class); - WebViewAppPicker webviewAppPicker = controller.get(); + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Activity mActivity; + @Mock + private UserManager mUserManager; + @Mock + private PackageManagerWrapper mPackageManager; - WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); - when(wvusWrapper.getValidWebViewApplicationInfos(any())).thenReturn( - Arrays.asList(createApplicationInfo(DEFAULT_PACKAGE_NAME))); - when(wvusWrapper.setWebViewProvider(eq(DEFAULT_PACKAGE_NAME))).thenReturn(true); + private WebViewAppPicker mPicker; + private WebViewUpdateServiceWrapper mWvusWrapper; - webviewAppPicker.setWebViewUpdateServiceWrapper(wvusWrapper); + private static ApplicationInfo createApplicationInfo(String packageName) { + ApplicationInfo ai = new ApplicationInfo(); + ai.packageName = packageName; + return ai; + } - controller.create().start().postCreate(null).resume().visible(); - WebViewApplicationInfo firstItem = - (WebViewApplicationInfo) webviewAppPicker.getListView().getItemAtPosition(0); - assertThat(firstItem.info.packageName).isEqualTo(DEFAULT_PACKAGE_NAME); + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(mActivity.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager); - webviewAppPicker.onListItemClick(webviewAppPicker.getListView(), null, 0, 0); + mPicker = new WebViewAppPicker(); + mPicker = spy(mPicker); + doNothing().when(mPicker).updateCandidates(); + doNothing().when(mPicker).updateCheckedState(any()); + doReturn(mActivity).when(mPicker).getActivity(); - verify(wvusWrapper, times(1)).setWebViewProvider(eq(DEFAULT_PACKAGE_NAME)); - assertThat(shadowOf(webviewAppPicker).getResultCode()).isEqualTo(Activity.RESULT_OK); - verify(wvusWrapper, never()).showInvalidChoiceToast(any()); - } + mWvusWrapper = mock(WebViewUpdateServiceWrapper.class); + mPicker.setWebViewUpdateServiceWrapper(mWvusWrapper); + } - @Test - public void testFailingPackageChangeReturnsCancelled() { - ActivityController controller = - Robolectric.buildActivity(WebViewAppPicker.class); - WebViewAppPicker webviewAppPicker = controller.get(); + @Test + public void testClickingItemChangesProvider() { + testSuccessfulClickChangesProvider(); + } - WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); - when(wvusWrapper.getValidWebViewApplicationInfos(any())).thenReturn( - Arrays.asList(createApplicationInfo(DEFAULT_PACKAGE_NAME))); - when(wvusWrapper.setWebViewProvider(eq(DEFAULT_PACKAGE_NAME))).thenReturn(false); + @Test + public void testFailingClick() { + testFailingClickUpdatesSetting(); + } - webviewAppPicker.setWebViewUpdateServiceWrapper(wvusWrapper); + @Test + public void testClickingItemInActivityModeChangesProviderAndFinishes() { + useWebViewSettingIntent(); + testSuccessfulClickChangesProvider(); + verify(mActivity, times(1)).finish(); + } - controller.create().start().postCreate(null).resume().visible(); - WebViewApplicationInfo firstItem = - (WebViewApplicationInfo) webviewAppPicker.getListView().getItemAtPosition(0); - assertThat(firstItem.info.packageName).isEqualTo(DEFAULT_PACKAGE_NAME); + @Test + public void testFailingClickInActivityMode() { + useWebViewSettingIntent(); + testFailingClick(); + } - webviewAppPicker.onListItemClick(webviewAppPicker.getListView(), null, 0, 0); + private void useWebViewSettingIntent() { + Intent intent = new Intent(ACTION_WEBVIEW_SETTINGS); + when(mActivity.getIntent()).thenReturn(intent); + } - verify(wvusWrapper, times(1)).setWebViewProvider(eq(DEFAULT_PACKAGE_NAME)); - assertThat(shadowOf(webviewAppPicker).getResultCode()).isEqualTo(Activity.RESULT_CANCELED); - verify(wvusWrapper, times(1)).showInvalidChoiceToast(any()); - } + private void testSuccessfulClickChangesProvider() { + when(mWvusWrapper.getValidWebViewApplicationInfos(any())).thenReturn( + Arrays.asList(createApplicationInfo(DEFAULT_PACKAGE_NAME))); + when(mWvusWrapper.setWebViewProvider(eq(DEFAULT_PACKAGE_NAME))).thenReturn(true); + + RadioButtonPreference defaultPackagePref = mock(RadioButtonPreference.class); + when(defaultPackagePref.getKey()).thenReturn(DEFAULT_PACKAGE_NAME); + mPicker.onRadioButtonClicked(defaultPackagePref); + + verify(mWvusWrapper, times(1)).setWebViewProvider(eq(DEFAULT_PACKAGE_NAME)); + verify(mPicker, times(1)).updateCheckedState(DEFAULT_PACKAGE_NAME); + verify(mWvusWrapper, never()).showInvalidChoiceToast(any()); + } + + private void testFailingClickUpdatesSetting() { + when(mWvusWrapper.getValidWebViewApplicationInfos(any())).thenReturn( + Arrays.asList(createApplicationInfo(DEFAULT_PACKAGE_NAME))); + when(mWvusWrapper.setWebViewProvider(eq(DEFAULT_PACKAGE_NAME))).thenReturn(false); + + RadioButtonPreference defaultPackagePref = mock(RadioButtonPreference.class); + when(defaultPackagePref.getKey()).thenReturn(DEFAULT_PACKAGE_NAME); + mPicker.onRadioButtonClicked(defaultPackagePref); + + verify(mWvusWrapper, times(1)).setWebViewProvider(eq(DEFAULT_PACKAGE_NAME)); + // Ensure we update the list of packages when we click a non-valid package - the list must + // have changed, otherwise this click wouldn't fail. + verify(mPicker, times(1)).updateCandidates(); + verify(mWvusWrapper, times(1)).showInvalidChoiceToast(any()); + } + + @Test + public void testFinishIfNotAdmin() { + doReturn(false).when(mUserManager).isAdminUser(); + mPicker.onAttach((Context) mActivity); + verify(mActivity, times(1)).finish(); + } + + @Test + public void testNotFinishedIfAdmin() { + doReturn(true).when(mUserManager).isAdminUser(); + mPicker.onAttach((Context) mActivity); + verify(mActivity, never()).finish(); + } + + @Test + public void testDisabledReasonNullIfPackagesOk() { + UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class); + when(packageForFirstUser.isEnabledPackage()).thenReturn(true); + when(packageForFirstUser.isInstalledPackage()).thenReturn(true); + + UserPackageWrapper packageForSecondUser = mock(UserPackageWrapper.class); + when(packageForSecondUser.isEnabledPackage()).thenReturn(true); + when(packageForSecondUser.isInstalledPackage()).thenReturn(true); + + WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); + when(wvusWrapper.getPackageInfosAllUsers( + any(), eq(DEFAULT_PACKAGE_NAME))).thenReturn( + Arrays.asList(packageForFirstUser, packageForSecondUser)); + + assertThat(mPicker.getDisabledReason(wvusWrapper, mContext, DEFAULT_PACKAGE_NAME)).isNull(); + } + + @Test + public void testDisabledReasonForSingleUserDisabledPackage() { + UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class); + when(packageForFirstUser.isEnabledPackage()).thenReturn(false); + when(packageForFirstUser.isInstalledPackage()).thenReturn(true); + when(packageForFirstUser.getUserInfo()).thenReturn(FIRST_USER); + + WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); + when(wvusWrapper.getPackageInfosAllUsers(any(), eq(DEFAULT_PACKAGE_NAME) + )).thenReturn(Arrays.asList(packageForFirstUser)); + + final String EXPECTED_DISABLED_REASON = String.format( + "(disabled for user %s)", FIRST_USER.name); + assertThat(mPicker.getDisabledReason(wvusWrapper, mContext, + DEFAULT_PACKAGE_NAME)).isEqualTo(EXPECTED_DISABLED_REASON); + } + + @Test + public void testDisabledReasonForSingleUserUninstalledPackage() { + UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class); + when(packageForFirstUser.isEnabledPackage()).thenReturn(true); + when(packageForFirstUser.isInstalledPackage()).thenReturn(false); + when(packageForFirstUser.getUserInfo()).thenReturn(FIRST_USER); + + WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); + when(wvusWrapper.getPackageInfosAllUsers(any(), eq(DEFAULT_PACKAGE_NAME) + )).thenReturn(Arrays.asList(packageForFirstUser)); + + final String EXPECTED_DISABLED_REASON = String.format( + "(uninstalled for user %s)", FIRST_USER.name); + assertThat(mPicker.getDisabledReason(wvusWrapper, mContext, + DEFAULT_PACKAGE_NAME)).isEqualTo(EXPECTED_DISABLED_REASON); + } + + @Test + public void testDisabledReasonSeveralUsers() { + UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class); + when(packageForFirstUser.isEnabledPackage()).thenReturn(false); + when(packageForFirstUser.isInstalledPackage()).thenReturn(true); + when(packageForFirstUser.getUserInfo()).thenReturn(FIRST_USER); + + UserPackageWrapper packageForSecondUser = mock(UserPackageWrapper.class); + when(packageForSecondUser.isEnabledPackage()).thenReturn(true); + when(packageForSecondUser.isInstalledPackage()).thenReturn(false); + when(packageForSecondUser.getUserInfo()).thenReturn(SECOND_USER); + + WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); + when(wvusWrapper.getPackageInfosAllUsers(any(), eq(DEFAULT_PACKAGE_NAME) + )).thenReturn(Arrays.asList(packageForFirstUser, packageForSecondUser)); + + final String EXPECTED_DISABLED_REASON = String.format( + "(disabled for user %s)", FIRST_USER.name); + assertThat(mPicker.getDisabledReason( + wvusWrapper, mContext,DEFAULT_PACKAGE_NAME)).isEqualTo(EXPECTED_DISABLED_REASON); + } + + /** + * Ensure we only proclaim a package as uninstalled for a certain user if it's both uninstalled + * and disabled. + */ + @Test + public void testDisabledReasonUninstalledAndDisabled() { + UserPackageWrapper packageForFirstUser = mock(UserPackageWrapper.class); + when(packageForFirstUser.isEnabledPackage()).thenReturn(false); + when(packageForFirstUser.isInstalledPackage()).thenReturn(false); + when(packageForFirstUser.getUserInfo()).thenReturn(FIRST_USER); + + UserPackageWrapper packageForSecondUser = mock(UserPackageWrapper.class); + when(packageForSecondUser.isEnabledPackage()).thenReturn(true); + when(packageForSecondUser.isInstalledPackage()).thenReturn(true); + when(packageForSecondUser.getUserInfo()).thenReturn(SECOND_USER); + + WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); + when(wvusWrapper.getPackageInfosAllUsers(any(), eq(DEFAULT_PACKAGE_NAME) + )).thenReturn(Arrays.asList(packageForFirstUser, packageForSecondUser)); + + final String EXPECTED_DISABLED_REASON = String.format( + "(uninstalled for user %s)", FIRST_USER.name); + assertThat(mPicker.getDisabledReason(wvusWrapper, mContext, + DEFAULT_PACKAGE_NAME)).isEqualTo(EXPECTED_DISABLED_REASON); + } } diff --git a/tests/robotests/src/com/android/settings/webview/WebViewAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/webview/WebViewAppPreferenceControllerTest.java index e0a32a4c3fd..d32f48645c9 100644 --- a/tests/robotests/src/com/android/settings/webview/WebViewAppPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/webview/WebViewAppPreferenceControllerTest.java @@ -14,21 +14,11 @@ package com.android.settings.webview; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.eq; +import static com.google.common.truth.Truth.assertThat; 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.Activity; import android.content.Context; -import android.content.Intent; import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceScreen; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; @@ -36,8 +26,6 @@ import com.android.settings.TestConfig; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; -import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.annotation.Config; @@ -45,39 +33,26 @@ import org.robolectric.annotation.Config; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class WebViewAppPreferenceControllerTest { - @Mock(answer = Answers.RETURNS_DEEP_STUBS) + @Mock private Context mContext; - @Mock - private PreferenceScreen mPreferenceScreen; - @Mock - private Preference mPreference; + private WebViewAppPreferenceController mController; private static final String DEFAULT_PACKAGE_NAME = "DEFAULT_PACKAGE_NAME"; - @Before public void setUp() { + @Before + public void setUp() { MockitoAnnotations.initMocks(this); - when(mPreferenceScreen.findPreference(any())).thenReturn(mPreference); + mController = new WebViewAppPreferenceController(mContext); } - @Test public void testOnActivityResultUpdatesStateOnSuccess() { - WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); - WebViewAppPreferenceController controller = - spy(new WebViewAppPreferenceController(mContext, wvusWrapper)); - - controller.displayPreference(mPreferenceScreen); // Makes sure Preference is non-null - controller.onActivityResult(Activity.RESULT_OK, new Intent(DEFAULT_PACKAGE_NAME)); - verify(controller, times(1)).updateState(any()); + @Test + public void testIsAlwaysAvailable() { + assertThat(mController.isAvailable()).isTrue(); } - @Test public void testOnActivityResultWithFailure() { - WebViewUpdateServiceWrapper wvusWrapper = mock(WebViewUpdateServiceWrapper.class); - - WebViewAppPreferenceController controller = - spy(new WebViewAppPreferenceController(mContext, wvusWrapper)); - - controller.displayPreference(mPreferenceScreen); // Makes sure Preference is non-null - controller.onActivityResult(Activity.RESULT_CANCELED, new Intent(DEFAULT_PACKAGE_NAME)); - verify(controller, times(1)).updateState(any()); + @Test + public void testNeverHandlesClick() { + assertThat(mController.handlePreferenceTreeClick(mock(Preference.class))).isFalse(); } }