From ddf359d0f81e76775ea6b285f8d58b8a64e3049a Mon Sep 17 00:00:00 2001 From: Becca Hughes Date: Mon, 24 Apr 2023 16:08:59 +0000 Subject: [PATCH] Fork autofill default app selection We are merging the default app selection for autofill with credman so this forks the existing UI (so we can flag it off). Test: ondevice Bug: 278919696 Change-Id: I96bcf1ff86b169a182b9974f7384c45b474c3d5d --- res/values/strings.xml | 16 ++ .../accounts_dashboard_settings_credman.xml | 6 +- ...ts_personal_dashboard_settings_credman.xml | 6 +- ...counts_work_dashboard_settings_credman.xml | 4 +- res/xml/default_credman_picker.xml | 20 ++ .../accounts/AccountDashboardFragment.java | 20 +- .../AccountPersonalDashboardFragment.java | 9 +- .../AccountWorkProfileDashboardFragment.java | 9 +- ...CredentialManagerPreferenceController.java | 90 ++++-- .../credentials/DefaultCombinedPicker.java | 258 ++++++++++++++++++ .../DefaultCombinedPreferenceController.java | 150 ++++++++++ ...faultWorkCombinedPreferenceController.java | 84 ++++++ ...entialManagerPreferenceControllerTest.java | 13 +- 13 files changed, 637 insertions(+), 48 deletions(-) create mode 100644 res/xml/default_credman_picker.xml create mode 100644 src/com/android/settings/applications/credentials/DefaultCombinedPicker.java create mode 100644 src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java create mode 100644 src/com/android/settings/applications/credentials/DefaultWorkCombinedPreferenceController.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 5d4487c42ca..d106737cda9 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -10265,6 +10265,8 @@ auto, fill, autofill, password data, passkey, password + + auto, fill, autofill, data, passkey, password @@ -10277,6 +10279,20 @@ ]]> + + + Use %1$s\? +
+
+ %1$s uses what\'s on + your screen to determine what can be autofilled. New passwords, passkeys and other info will be saved here from now on. + ]]> +
+ + + Passwords, passkeys and data services + Turn off %1$s\? diff --git a/res/xml/accounts_dashboard_settings_credman.xml b/res/xml/accounts_dashboard_settings_credman.xml index 4f278b659b2..83c16a2df30 100644 --- a/res/xml/accounts_dashboard_settings_credman.xml +++ b/res/xml/accounts_dashboard_settings_credman.xml @@ -27,10 +27,10 @@ android:title="@string/credman_chosen_app_title"> + settings:keywords="@string/credman_autofill_keywords"> diff --git a/res/xml/accounts_personal_dashboard_settings_credman.xml b/res/xml/accounts_personal_dashboard_settings_credman.xml index 891bb7c1d22..b87e866700b 100644 --- a/res/xml/accounts_personal_dashboard_settings_credman.xml +++ b/res/xml/accounts_personal_dashboard_settings_credman.xml @@ -28,10 +28,10 @@ android:title="@string/credman_chosen_app_title"> + settings:keywords="@string/credman_autofill_keywords"> diff --git a/res/xml/accounts_work_dashboard_settings_credman.xml b/res/xml/accounts_work_dashboard_settings_credman.xml index 0d4b742c366..15299208a4e 100644 --- a/res/xml/accounts_work_dashboard_settings_credman.xml +++ b/res/xml/accounts_work_dashboard_settings_credman.xml @@ -28,8 +28,8 @@ android:title="@string/credman_chosen_app_title"> + + + diff --git a/src/com/android/settings/accounts/AccountDashboardFragment.java b/src/com/android/settings/accounts/AccountDashboardFragment.java index f59de46428d..e4c20313a54 100644 --- a/src/com/android/settings/accounts/AccountDashboardFragment.java +++ b/src/com/android/settings/accounts/AccountDashboardFragment.java @@ -30,6 +30,8 @@ import android.provider.SearchIndexableResource; import com.android.settings.R; import com.android.settings.applications.autofill.PasswordsPreferenceController; import com.android.settings.applications.credentials.CredentialManagerPreferenceController; +import com.android.settings.applications.credentials.DefaultCombinedPreferenceController; +import com.android.settings.applications.credentials.DefaultWorkCombinedPreferenceController; import com.android.settings.applications.defaultapps.DefaultAutofillPreferenceController; import com.android.settings.applications.defaultapps.DefaultWorkAutofillPreferenceController; import com.android.settings.dashboard.DashboardFragment; @@ -76,7 +78,14 @@ public class AccountDashboardFragment extends DashboardFragment { CredentialManagerPreferenceController cmpp = use(CredentialManagerPreferenceController.class); CredentialManagerPreferenceController.Delegate delegate = - result -> getActivity().setResult(result); + new CredentialManagerPreferenceController.Delegate() { + public void setActivityResult(int resultCode) { + getActivity().setResult(resultCode); + } + public void forceDelegateRefresh() { + forceUpdatePreferences(); + } + }; cmpp.init(this, getFragmentManager(), getIntent(), delegate); } else { getSettingsLifecycle().addObserver(use(PasswordsPreferenceController.class)); @@ -99,8 +108,13 @@ public class AccountDashboardFragment extends DashboardFragment { static void buildAutofillPreferenceControllers( Context context, List controllers) { - controllers.add(new DefaultAutofillPreferenceController(context)); - controllers.add(new DefaultWorkAutofillPreferenceController(context)); + if (CredentialManager.isServiceEnabled(context)) { + controllers.add(new DefaultCombinedPreferenceController(context)); + controllers.add(new DefaultWorkCombinedPreferenceController(context)); + } else { + controllers.add(new DefaultAutofillPreferenceController(context)); + controllers.add(new DefaultWorkAutofillPreferenceController(context)); + } } private static void buildAccountPreferenceControllers( diff --git a/src/com/android/settings/accounts/AccountPersonalDashboardFragment.java b/src/com/android/settings/accounts/AccountPersonalDashboardFragment.java index a87eb7dd774..d330dd49ec6 100644 --- a/src/com/android/settings/accounts/AccountPersonalDashboardFragment.java +++ b/src/com/android/settings/accounts/AccountPersonalDashboardFragment.java @@ -70,7 +70,14 @@ public class AccountPersonalDashboardFragment extends DashboardFragment { CredentialManagerPreferenceController cmpp = use(CredentialManagerPreferenceController.class); CredentialManagerPreferenceController.Delegate delegate = - result -> getActivity().setResult(result); + new CredentialManagerPreferenceController.Delegate() { + public void setActivityResult(int resultCode) { + getActivity().setResult(resultCode); + } + public void forceDelegateRefresh() { + forceUpdatePreferences(); + } + }; cmpp.init(this, getFragmentManager(), getIntent(), delegate); } else { getSettingsLifecycle().addObserver(use(PasswordsPreferenceController.class)); diff --git a/src/com/android/settings/accounts/AccountWorkProfileDashboardFragment.java b/src/com/android/settings/accounts/AccountWorkProfileDashboardFragment.java index 445aced18d0..39146c75a7c 100644 --- a/src/com/android/settings/accounts/AccountWorkProfileDashboardFragment.java +++ b/src/com/android/settings/accounts/AccountWorkProfileDashboardFragment.java @@ -70,7 +70,14 @@ public class AccountWorkProfileDashboardFragment extends DashboardFragment { CredentialManagerPreferenceController cmpp = use(CredentialManagerPreferenceController.class); CredentialManagerPreferenceController.Delegate delegate = - result -> getActivity().setResult(result); + new CredentialManagerPreferenceController.Delegate() { + public void setActivityResult(int resultCode) { + getActivity().setResult(resultCode); + } + public void forceDelegateRefresh() { + forceUpdatePreferences(); + } + }; cmpp.init(this, getFragmentManager(), getIntent(), delegate); } else { getSettingsLifecycle().addObserver(use(PasswordsPreferenceController.class)); diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java index f19fb91fccc..944a9fa551b 100644 --- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java +++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java @@ -44,8 +44,6 @@ import android.os.UserHandle; import android.provider.DeviceConfig; import android.provider.Settings; import android.text.TextUtils; -import com.android.settingslib.utils.ThreadUtils; -import com.android.internal.content.PackageMonitor; import android.util.IconDrawableFactory; import android.util.Log; @@ -127,6 +125,23 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl return null; } + @Override + public int getAvailabilityStatus() { + if (mCredentialManager == null) { + return UNSUPPORTED_ON_DEVICE; + } + + if (!isAutofillPrefSelected()) { + return CONDITIONALLY_UNAVAILABLE; + } + + if (mServices.isEmpty()) { + return CONDITIONALLY_UNAVAILABLE; + } + + return AVAILABLE; + } + @VisibleForTesting public boolean isConnected() { return mCredentialManager != null; @@ -266,12 +281,15 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl if (mPreferenceScreen != null) { displayPreference(mPreferenceScreen); } + + if (mDelegate != null) { + mDelegate.forceDelegateRefresh(); + } } @VisibleForTesting void setAvailableServices( - List availableServices, - String flagOverrideForTest) { + List availableServices, String flagOverrideForTest) { mFlagOverrideForTest = flagOverrideForTest; mServices.clear(); mServices.addAll(availableServices); @@ -291,11 +309,6 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl } } - @Override - public int getAvailabilityStatus() { - return mServices.isEmpty() ? CONDITIONALLY_UNAVAILABLE : AVAILABLE; - } - @Override public void displayPreference(PreferenceScreen screen) { super.displayPreference(screen); @@ -305,6 +318,17 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl mPreferenceScreen = screen; PreferenceGroup group = screen.findPreference(getPreferenceKey()); + group.removeAll(); + + // Hide/show based on autofill pref. + boolean isVisible = isAutofillPrefSelected(); + screen.setVisible(isVisible); + group.setVisible(isVisible); + + if (!isVisible) { + return; + } + Context context = screen.getContext(); mPrefs.putAll(buildPreferenceList(context, group)); @@ -586,10 +610,9 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl /** If the provider is also the autofill provider then hide it. */ @VisibleForTesting public boolean isProviderHiddenBecauseOfAutofill(String packageName) { - final String autofillService = Settings.Secure.getStringForUser( - mContext.getContentResolver(), - Settings.Secure.AUTOFILL_SERVICE, - getUser()); + final String autofillService = + Settings.Secure.getStringForUser( + mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, getUser()); if (autofillService == null || TextUtils.isEmpty(autofillService)) { return false; } @@ -600,6 +623,13 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl return autofillService.startsWith(packageName); } + private boolean isAutofillPrefSelected() { + final String autofillService = + Settings.Secure.getStringForUser( + mContext.getContentResolver(), Settings.Secure.AUTOFILL_SERVICE, getUser()); + return !TextUtils.isEmpty(autofillService); + } + @VisibleForTesting void completeEnableProviderDialogBox( int whichButton, String packageName, boolean setActivityResult) { @@ -682,27 +712,31 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl /** Called to send messages back to the parent fragment. */ public static interface Delegate { void setActivityResult(int resultCode); + + void forceDelegateRefresh(); } /** - * Monitor coming and going credman services and calls {@link #update()} when necessary + * Monitor coming and going credman services and calls {@link #DefaultCombinedPicker} when + * necessary */ - private final PackageMonitor mSettingsPackageMonitor = new PackageMonitor() { - @Override - public void onPackageAdded(String packageName, int uid) { - ThreadUtils.postOnMainThread(() -> update()); - } + private final PackageMonitor mSettingsPackageMonitor = + new PackageMonitor() { + @Override + public void onPackageAdded(String packageName, int uid) { + ThreadUtils.postOnMainThread(() -> updateFromExternal()); + } - @Override - public void onPackageModified(String packageName) { - ThreadUtils.postOnMainThread(() -> update()); - } + @Override + public void onPackageModified(String packageName) { + ThreadUtils.postOnMainThread(() -> updateFromExternal()); + } - @Override - public void onPackageRemoved(String packageName, int uid) { - ThreadUtils.postOnMainThread(() -> update()); - } - }; + @Override + public void onPackageRemoved(String packageName, int uid) { + ThreadUtils.postOnMainThread(() -> updateFromExternal()); + } + }; /** Dialog fragment parent class. */ private abstract static class CredentialManagerDialogFragment extends DialogFragment diff --git a/src/com/android/settings/applications/credentials/DefaultCombinedPicker.java b/src/com/android/settings/applications/credentials/DefaultCombinedPicker.java new file mode 100644 index 00000000000..41eaf9657a4 --- /dev/null +++ b/src/com/android/settings/applications/credentials/DefaultCombinedPicker.java @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2023 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.credentials; + +import android.app.Activity; +import android.app.settings.SettingsEnums; +import android.content.ComponentName; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.UserHandle; +import android.provider.Settings; +import android.service.autofill.AutofillService; +import android.service.autofill.AutofillServiceInfo; +import android.text.Html; +import android.text.TextUtils; + +import androidx.preference.Preference; + +import com.android.internal.content.PackageMonitor; +import com.android.settings.R; +import com.android.settings.applications.defaultapps.DefaultAppPickerFragment; +import com.android.settingslib.applications.DefaultAppInfo; +import com.android.settingslib.utils.ThreadUtils; +import com.android.settingslib.widget.CandidateInfo; + +import java.util.ArrayList; +import java.util.List; + +public class DefaultCombinedPicker extends DefaultAppPickerFragment { + + private static final String TAG = "DefaultCombinedPicker"; + + public static final String SETTING = Settings.Secure.AUTOFILL_SERVICE; + public static final Intent AUTOFILL_PROBE = new Intent(AutofillService.SERVICE_INTERFACE); + + /** Extra set when the fragment is implementing ACTION_REQUEST_SET_AUTOFILL_SERVICE. */ + public static final String EXTRA_PACKAGE_NAME = "package_name"; + + /** Set when the fragment is implementing ACTION_REQUEST_SET_AUTOFILL_SERVICE. */ + private DialogInterface.OnClickListener mCancelListener; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final Activity activity = getActivity(); + if (activity != null && activity.getIntent().getStringExtra(EXTRA_PACKAGE_NAME) != null) { + mCancelListener = + (d, w) -> { + activity.setResult(Activity.RESULT_CANCELED); + activity.finish(); + }; + // If mCancelListener is not null, fragment is started from + // ACTION_REQUEST_SET_AUTOFILL_SERVICE and we should always use the calling uid. + mUserId = UserHandle.myUserId(); + } + mSettingsPackageMonitor.register(activity, activity.getMainLooper(), false); + update(); + } + + @Override + protected DefaultAppPickerFragment.ConfirmationDialogFragment newConfirmationDialogFragment( + String selectedKey, CharSequence confirmationMessage) { + final AutofillPickerConfirmationDialogFragment fragment = + new AutofillPickerConfirmationDialogFragment(); + fragment.init(this, selectedKey, confirmationMessage); + return fragment; + } + + /** + * Custom dialog fragment that has a cancel listener used to propagate the result back to caller + * (for the cases where the picker is launched by {@code + * android.settings.REQUEST_SET_AUTOFILL_SERVICE}. + */ + public static class AutofillPickerConfirmationDialogFragment + extends DefaultAppPickerFragment.ConfirmationDialogFragment { + + @Override + public void onCreate(Bundle savedInstanceState) { + final DefaultCombinedPicker target = (DefaultCombinedPicker) getTargetFragment(); + setCancelListener(target.mCancelListener); + super.onCreate(savedInstanceState); + } + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.default_credman_picker; + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.DEFAULT_AUTOFILL_PICKER; + } + + @Override + protected boolean shouldShowItemNone() { + return true; + } + + /** Monitor coming and going auto fill services and calls {@link #update()} when necessary */ + private final PackageMonitor mSettingsPackageMonitor = + new PackageMonitor() { + @Override + public void onPackageAdded(String packageName, int uid) { + ThreadUtils.postOnMainThread(() -> update()); + } + + @Override + public void onPackageModified(String packageName) { + ThreadUtils.postOnMainThread(() -> update()); + } + + @Override + public void onPackageRemoved(String packageName, int uid) { + ThreadUtils.postOnMainThread(() -> update()); + } + }; + + /** Update the data in this UI. */ + private void update() { + updateCandidates(); + addAddServicePreference(); + } + + @Override + public void onDestroy() { + mSettingsPackageMonitor.unregister(); + super.onDestroy(); + } + + /** + * Gets the preference that allows to add a new autofill service. + * + * @return The preference or {@code null} if no service can be added + */ + private Preference newAddServicePreferenceOrNull() { + final String searchUri = + Settings.Secure.getStringForUser( + getActivity().getContentResolver(), + Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI, + mUserId); + if (TextUtils.isEmpty(searchUri)) { + return null; + } + + final Intent addNewServiceIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(searchUri)); + final Context context = getPrefContext(); + final Preference preference = new Preference(context); + preference.setOnPreferenceClickListener( + p -> { + context.startActivityAsUser(addNewServiceIntent, UserHandle.of(mUserId)); + return true; + }); + preference.setTitle(R.string.print_menu_item_add_service); + preference.setIcon(R.drawable.ic_add_24dp); + preference.setOrder(Integer.MAX_VALUE - 1); + preference.setPersistent(false); + return preference; + } + + /** + * Add a preference that allows the user to add a service if the market link for that is + * configured. + */ + private void addAddServicePreference() { + final Preference addNewServicePreference = newAddServicePreferenceOrNull(); + if (addNewServicePreference != null) { + getPreferenceScreen().addPreference(addNewServicePreference); + } + } + + @Override + protected List getCandidates() { + final List candidates = new ArrayList<>(); + final List services = + AutofillServiceInfo.getAvailableServices(getContext(), mUserId); + for (AutofillServiceInfo asi : services) { + candidates.add( + new DefaultAppInfo( + getContext(), mPm, mUserId, asi.getServiceInfo().getComponentName())); + } + + return candidates; + } + + public static String getDefaultKey(Context context, int userId) { + String setting = + Settings.Secure.getStringForUser(context.getContentResolver(), SETTING, userId); + if (setting != null) { + ComponentName componentName = ComponentName.unflattenFromString(setting); + if (componentName != null) { + return componentName.flattenToString(); + } + } + return null; + } + + @Override + protected String getDefaultKey() { + return getDefaultKey(getContext(), mUserId); + } + + @Override + protected CharSequence getConfirmationMessage(CandidateInfo appInfo) { + if (appInfo == null) { + return null; + } + final CharSequence appName = appInfo.loadLabel(); + final String message = + getContext() + .getString( + R.string.credman_autofill_confirmation_message, + Html.escapeHtml(appName)); + return Html.fromHtml(message); + } + + @Override + protected boolean setDefaultKey(String key) { + Settings.Secure.putStringForUser(getContext().getContentResolver(), SETTING, key, mUserId); + + // Check if activity was launched from Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE + // intent, and set proper result if so... + final Activity activity = getActivity(); + if (activity != null) { + final String packageName = activity.getIntent().getStringExtra(EXTRA_PACKAGE_NAME); + if (packageName != null) { + final int result = + key != null && key.startsWith(packageName) + ? Activity.RESULT_OK + : Activity.RESULT_CANCELED; + activity.setResult(result); + activity.finish(); + } + } + + // TODO: Notify the rest + + return true; + } +} diff --git a/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java b/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java new file mode 100644 index 00000000000..00125a02342 --- /dev/null +++ b/src/com/android/settings/applications/credentials/DefaultCombinedPreferenceController.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2023 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.credentials; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; +import android.credentials.CredentialManager; +import android.provider.Settings; +import android.service.autofill.AutofillServiceInfo; +import android.text.TextUtils; +import android.util.Log; +import android.view.autofill.AutofillManager; + +import com.android.settings.applications.defaultapps.DefaultAppPreferenceController; +import com.android.settingslib.applications.DefaultAppInfo; + +import java.util.List; + +public class DefaultCombinedPreferenceController extends DefaultAppPreferenceController { + + private final AutofillManager mAutofillManager; + private final CredentialManager mCredentialManager; + + public DefaultCombinedPreferenceController(Context context) { + super(context); + + mAutofillManager = mContext.getSystemService(AutofillManager.class); + + if (CredentialManager.isServiceEnabled(context)) { + mCredentialManager = mContext.getSystemService(CredentialManager.class); + } else { + mCredentialManager = null; + } + } + + @Override + public boolean isAvailable() { + return mAutofillManager != null + && mCredentialManager != null + && mAutofillManager.hasAutofillFeature() + && mAutofillManager.isAutofillSupported(); + } + + @Override + public String getPreferenceKey() { + return "default_credman_autofill_main"; + } + + @Override + protected Intent getSettingIntent(DefaultAppInfo info) { + if (info == null) { + return null; + } + final AutofillSettingIntentProvider intentProvider = + new AutofillSettingIntentProvider(mContext, mUserId, info.getKey()); + return intentProvider.getIntent(); + } + + @Override + protected DefaultAppInfo getDefaultAppInfo() { + final String flattenComponent = + Settings.Secure.getString( + mContext.getContentResolver(), DefaultCombinedPicker.SETTING); + if (!TextUtils.isEmpty(flattenComponent)) { + DefaultAppInfo appInfo = + new DefaultAppInfo( + mContext, + mPackageManager, + mUserId, + ComponentName.unflattenFromString(flattenComponent)); + return appInfo; + } + return null; + } + + @Override + protected boolean showLabelAsTitle() { + return true; + } + + /** Provides Intent to setting activity for the specified autofill service. */ + static final class AutofillSettingIntentProvider { + + private final String mSelectedKey; + private final Context mContext; + private final int mUserId; + + public AutofillSettingIntentProvider(Context context, int userId, String key) { + mSelectedKey = key; + mContext = context; + mUserId = userId; + } + + public Intent getIntent() { + final List resolveInfos = + mContext.getPackageManager() + .queryIntentServicesAsUser( + DefaultCombinedPicker.AUTOFILL_PROBE, + PackageManager.GET_META_DATA, + mUserId); + + for (ResolveInfo resolveInfo : resolveInfos) { + final ServiceInfo serviceInfo = resolveInfo.serviceInfo; + final String flattenKey = + new ComponentName(serviceInfo.packageName, serviceInfo.name) + .flattenToString(); + if (TextUtils.equals(mSelectedKey, flattenKey)) { + final String settingsActivity; + try { + settingsActivity = + new AutofillServiceInfo(mContext, serviceInfo) + .getSettingsActivity(); + } catch (SecurityException e) { + // Service does not declare the proper permission, ignore it. + Log.w( + "AutofillSettingIntentProvider", + "Error getting info for " + serviceInfo + ": " + e); + return null; + } + if (TextUtils.isEmpty(settingsActivity)) { + return null; + } + return new Intent(Intent.ACTION_MAIN) + .setComponent( + new ComponentName(serviceInfo.packageName, settingsActivity)); + } + } + + return null; + } + } +} diff --git a/src/com/android/settings/applications/credentials/DefaultWorkCombinedPreferenceController.java b/src/com/android/settings/applications/credentials/DefaultWorkCombinedPreferenceController.java new file mode 100644 index 00000000000..cc41e971071 --- /dev/null +++ b/src/com/android/settings/applications/credentials/DefaultWorkCombinedPreferenceController.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2023 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.credentials; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.os.UserHandle; +import android.provider.Settings; +import android.text.TextUtils; + +import com.android.settings.Utils; +import com.android.settingslib.applications.DefaultAppInfo; + +public class DefaultWorkCombinedPreferenceController extends DefaultCombinedPreferenceController { + private final UserHandle mUserHandle; + + public DefaultWorkCombinedPreferenceController(Context context) { + super(context); + mUserHandle = Utils.getManagedProfile(mUserManager); + } + + @Override + public boolean isAvailable() { + if (mUserHandle == null) { + return false; + } + return super.isAvailable(); + } + + @Override + public String getPreferenceKey() { + return "default_autofill_work"; + } + + @Override + protected DefaultAppInfo getDefaultAppInfo() { + final String flattenComponent = + Settings.Secure.getStringForUser( + mContext.getContentResolver(), + DefaultCombinedPicker.SETTING, + mUserHandle.getIdentifier()); + if (!TextUtils.isEmpty(flattenComponent)) { + DefaultAppInfo appInfo = + new DefaultAppInfo( + mContext, + mPackageManager, + mUserHandle.getIdentifier(), + ComponentName.unflattenFromString(flattenComponent)); + return appInfo; + } + return null; + } + + @Override + protected Intent getSettingIntent(DefaultAppInfo info) { + if (info == null) { + return null; + } + final AutofillSettingIntentProvider intentProvider = + new AutofillSettingIntentProvider( + mContext, mUserHandle.getIdentifier(), info.getKey()); + return intentProvider.getIntent(); + } + + @Override + protected void startActivity(Intent intent) { + mContext.startActivityAsUser(intent, mUserHandle); + } +} diff --git a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java index 3145cce1ac6..60c7d45645a 100644 --- a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java @@ -86,13 +86,12 @@ public class CredentialManagerPreferenceControllerTest { mCredentialsPreferenceCategory.setKey("credentials_test"); mScreen.addPreference(mCredentialsPreferenceCategory); mReceivedResultCode = Optional.empty(); - mDelegate = - new CredentialManagerPreferenceController.Delegate() { - @Override - public void setActivityResult(int resultCode) { - mReceivedResultCode = Optional.of(resultCode); - } - }; + mDelegate = new CredentialManagerPreferenceController.Delegate() { + public void setActivityResult(int resultCode) { + mReceivedResultCode = Optional.of(resultCode); + } + public void forceDelegateRefresh() {} + }; } @Test