From 828409a79d03c87849692dea1ad3b10f26a09c21 Mon Sep 17 00:00:00 2001 From: "stanley.tf_wang" Date: Fri, 13 Apr 2018 16:18:13 +0800 Subject: [PATCH] Modified the ManageDomainUrls Test: manual Test: make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.applications make RunSettingsRoboTests -j ROBOTEST_FILTER=com.android.settings.core atest UniquePreferenceTest atest SettingsGatewayTest Change-Id: Ib5b1281be6cb3cab8528d10b6d6ff3146f33b8df --- AndroidManifest.xml | 2 +- res/xml/app_default_settings.xml | 2 +- res/xml/manage_domain_url_settings.xml | 25 +- .../applications/ManageDomainUrls.java | 294 ------------------ .../managedomainurls/DomainAppPreference.java | 106 +++++++ .../DomainAppPreferenceController.java | 172 ++++++++++ ...InstantAppAccountPreferenceController.java | 71 +++++ ...stantAppWebActionPreferenceController.java | 46 +++ .../managedomainurls/ManageDomainUrls.java | 77 +++++ .../WebActionCategoryController.java | 39 +++ .../core/gateway/SettingsGateway.java | 6 +- .../grandfather_not_implementing_indexable | 1 - .../DomainAppPreferenceControllerTest.java} | 15 +- ...antAppAccountPreferenceControllerTest.java | 97 ++++++ ...tAppWebActionPreferenceControllerTest.java | 96 ++++++ 15 files changed, 739 insertions(+), 310 deletions(-) delete mode 100644 src/com/android/settings/applications/ManageDomainUrls.java create mode 100644 src/com/android/settings/applications/managedomainurls/DomainAppPreference.java create mode 100644 src/com/android/settings/applications/managedomainurls/DomainAppPreferenceController.java create mode 100644 src/com/android/settings/applications/managedomainurls/InstantAppAccountPreferenceController.java create mode 100644 src/com/android/settings/applications/managedomainurls/InstantAppWebActionPreferenceController.java create mode 100644 src/com/android/settings/applications/managedomainurls/ManageDomainUrls.java create mode 100644 src/com/android/settings/applications/managedomainurls/WebActionCategoryController.java rename tests/robotests/src/com/android/settings/applications/{ManageDomainUrlsTest.java => managedomainurls/DomainAppPreferenceControllerTest.java} (86%) create mode 100644 tests/robotests/src/com/android/settings/applications/managedomainurls/InstantAppAccountPreferenceControllerTest.java create mode 100644 tests/robotests/src/com/android/settings/applications/managedomainurls/InstantAppWebActionPreferenceControllerTest.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index a21d0561acd..5fbecc3ffac 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1070,7 +1070,7 @@ + android:value="com.android.settings.applications.managedomainurls.ManageDomainUrls" /> + xmlns:settings="http://schemas.android.com/apk/res-auto" + android:title="@string/domain_urls_title" + android:key="manage_domain_url_screen"> + + + + + + + + \ No newline at end of file diff --git a/src/com/android/settings/applications/ManageDomainUrls.java b/src/com/android/settings/applications/ManageDomainUrls.java deleted file mode 100644 index e47792d8c42..00000000000 --- a/src/com/android/settings/applications/ManageDomainUrls.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language governing - * permissions and limitations under the License. - */ - -package com.android.settings.applications; - -import android.app.Application; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.os.Bundle; -import android.os.UserHandle; -import android.provider.Settings; -import android.provider.Settings.Global; -import androidx.annotation.VisibleForTesting; -import androidx.preference.SwitchPreference; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.Preference.OnPreferenceClickListener; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceGroup; -import androidx.preference.PreferenceViewHolder; -import android.util.ArraySet; -import android.view.View; - -import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; -import com.android.settings.Utils; -import com.android.settings.widget.AppPreference; -import com.android.settingslib.applications.ApplicationsState; -import com.android.settingslib.applications.ApplicationsState.AppEntry; - -import java.util.ArrayList; - -/** - * Activity to manage how Android handles URL resolution. Includes both per-app - * handling as well as system handling for Web Actions. - */ -public class ManageDomainUrls extends SettingsPreferenceFragment - implements ApplicationsState.Callbacks, OnPreferenceChangeListener, - OnPreferenceClickListener { - - // constant value that can be used to check return code from sub activity. - private static final int INSTALLED_APP_DETAILS = 1; - - private ApplicationsState mApplicationsState; - private ApplicationsState.Session mSession; - private PreferenceGroup mDomainAppList; - private SwitchPreference mWebAction; - private Preference mInstantAppAccountPreference; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - setAnimationAllowed(true); - mApplicationsState = ApplicationsState.getInstance( - (Application) getContext().getApplicationContext()); - mSession = mApplicationsState.newSession(this, getLifecycle()); - setHasOptionsMenu(true); - } - - @Override - protected int getPreferenceScreenResId() { - return R.xml.manage_domain_url_settings; - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - } - - @Override - public void onRunningStateChanged(boolean running) { - } - - @Override - public void onPackageListChanged() { - } - - @Override - public void onRebuildComplete(ArrayList apps) { - if (getContext() == null) { - return; - } - - final boolean disableWebActions = Global.getInt(getContext().getContentResolver(), - Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0; - if (disableWebActions) { - mDomainAppList = getPreferenceScreen(); - } else { - final PreferenceGroup preferenceScreen = getPreferenceScreen(); - if (preferenceScreen.getPreferenceCount() == 0) { - // add preferences - final PreferenceCategory webActionCategory = - new PreferenceCategory(getPrefContext()); - webActionCategory.setTitle(R.string.web_action_section_title); - preferenceScreen.addPreference(webActionCategory); - - // toggle to enable / disable Web Actions [aka Instant Apps] - mWebAction = new SwitchPreference(getPrefContext()); - mWebAction.setTitle(R.string.web_action_enable_title); - mWebAction.setSummary(R.string.web_action_enable_summary); - mWebAction.setChecked(Settings.Secure.getInt(getContentResolver(), - Settings.Secure.INSTANT_APPS_ENABLED, 1) != 0); - mWebAction.setOnPreferenceChangeListener(this); - webActionCategory.addPreference(mWebAction); - - // Determine whether we should show the instant apps account chooser setting - ComponentName instantAppSettingsComponent = getActivity().getPackageManager() - .getInstantAppResolverSettingsComponent(); - Intent instantAppSettingsIntent = null; - if (instantAppSettingsComponent != null) { - instantAppSettingsIntent = - new Intent().setComponent(instantAppSettingsComponent); - } - if (instantAppSettingsIntent != null) { - final Intent launchIntent = instantAppSettingsIntent; - // TODO: Make this button actually launch the account chooser. - mInstantAppAccountPreference = new Preference(getPrefContext()); - mInstantAppAccountPreference.setTitle(R.string.instant_apps_settings); - mInstantAppAccountPreference.setOnPreferenceClickListener(pref -> { - startActivity(launchIntent); - return true; - }); - webActionCategory.addPreference(mInstantAppAccountPreference); - } - - // list to manage link handling per app - mDomainAppList = new PreferenceCategory(getPrefContext()); - mDomainAppList.setTitle(R.string.domain_url_section_title); - preferenceScreen.addPreference(mDomainAppList); - } - } - rebuildAppList(mDomainAppList, apps); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - if (preference == mWebAction) { - boolean checked = (boolean) newValue; - Settings.Secure.putInt( - getContentResolver(), - Settings.Secure.INSTANT_APPS_ENABLED, checked ? 1 : 0); - return true; - } - return false; - } - - private void rebuild() { - final ArrayList apps = mSession.rebuild( - ApplicationsState.FILTER_WITH_DOMAIN_URLS, ApplicationsState.ALPHA_COMPARATOR); - if (apps != null) { - onRebuildComplete(apps); - } - } - - private void rebuildAppList(PreferenceGroup group, ArrayList apps) { - cacheRemoveAllPrefs(group); - final int N = apps.size(); - for (int i = 0; i < N; i++) { - AppEntry entry = apps.get(i); - String key = entry.info.packageName + "|" + entry.info.uid; - DomainAppPreference preference = (DomainAppPreference) getCachedPreference(key); - if (preference == null) { - preference = new DomainAppPreference(getPrefContext(), mApplicationsState, entry); - preference.setKey(key); - preference.setOnPreferenceClickListener(this); - group.addPreference(preference); - } else { - preference.reuse(); - } - preference.setOrder(i); - } - removeCachedPrefs(group); - } - - @Override - public void onPackageIconChanged() { - } - - @Override - public void onPackageSizeChanged(String packageName) { - } - - @Override - public void onAllSizesComputed() { - } - - @Override - public void onLauncherInfoChanged() { - } - - @Override - public void onLoadEntriesCompleted() { - rebuild(); - } - - @Override - public int getMetricsCategory() { - return MetricsEvent.MANAGE_DOMAIN_URLS; - } - - @Override - public boolean onPreferenceClick(Preference preference) { - if (preference.getClass() == DomainAppPreference.class) { - ApplicationsState.AppEntry entry = ((DomainAppPreference) preference).mEntry; - AppInfoBase.startAppInfoFragment(AppLaunchSettings.class, R.string.auto_launch_label, - entry.info.packageName, entry.info.uid, this, - INSTALLED_APP_DETAILS, getMetricsCategory()); - return true; - } - return false; - } - - @VisibleForTesting - static class DomainAppPreference extends AppPreference { - private final AppEntry mEntry; - private final PackageManager mPm; - private final ApplicationsState mApplicationsState; - - public DomainAppPreference(final Context context, ApplicationsState applicationsState, - AppEntry entry) { - super(context); - mApplicationsState = applicationsState; - mPm = context.getPackageManager(); - mEntry = entry; - mEntry.ensureLabel(getContext()); - setState(); - if (mEntry.icon != null) { - setIcon(mEntry.icon); - } - } - - private void setState() { - setTitle(mEntry.label); - setSummary(getDomainsSummary(mEntry.info.packageName)); - } - - public void reuse() { - setState(); - notifyChanged(); - } - - @Override - public void onBindViewHolder(PreferenceViewHolder holder) { - if (mEntry.icon == null) { - holder.itemView.post(new Runnable() { - @Override - public void run() { - // Ensure we have an icon before binding. - mApplicationsState.ensureIcon(mEntry); - // This might trigger us to bind again, but it gives an easy way to only - // load the icon once its needed, so its probably worth it. - setIcon(mEntry.icon); - } - }); - } - super.onBindViewHolder(holder); - holder.itemView.findViewById(R.id.appendix).setVisibility(View.GONE); - } - - private CharSequence getDomainsSummary(String packageName) { - // If the user has explicitly said "no" for this package, that's the - // string we should show. - int domainStatus = - mPm.getIntentVerificationStatusAsUser(packageName, UserHandle.myUserId()); - if (domainStatus == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { - return getContext().getString(R.string.domain_urls_summary_none); - } - // Otherwise, ask package manager for the domains for this package, - // and show the first one (or none if there aren't any). - ArraySet result = Utils.getHandledDomains(mPm, packageName); - if (result.size() == 0) { - return getContext().getString(R.string.domain_urls_summary_none); - } else if (result.size() == 1) { - return getContext().getString(R.string.domain_urls_summary_one, result.valueAt(0)); - } else { - return getContext().getString(R.string.domain_urls_summary_some, result.valueAt(0)); - } - } - } -} diff --git a/src/com/android/settings/applications/managedomainurls/DomainAppPreference.java b/src/com/android/settings/applications/managedomainurls/DomainAppPreference.java new file mode 100644 index 00000000000..e1f1e92cd0c --- /dev/null +++ b/src/com/android/settings/applications/managedomainurls/DomainAppPreference.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2018 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.managedomainurls; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.UserHandle; +import android.util.ArraySet; +import android.view.View; + +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.widget.AppPreference; +import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.PreferenceViewHolder; + +@VisibleForTesting +public class DomainAppPreference extends AppPreference { + private final AppEntry mEntry; + private final PackageManager mPm; + private final ApplicationsState mApplicationsState; + + public DomainAppPreference(final Context context, ApplicationsState applicationsState, + AppEntry entry) { + super(context); + mApplicationsState = applicationsState; + mPm = context.getPackageManager(); + mEntry = entry; + mEntry.ensureLabel(getContext()); + setState(); + if (mEntry.icon != null) { + setIcon(mEntry.icon); + } + } + + @Override + public void onBindViewHolder(PreferenceViewHolder holder) { + if (mEntry.icon == null) { + holder.itemView.post(new Runnable() { + @Override + public void run() { + // Ensure we have an icon before binding. + if (mApplicationsState != null) { + mApplicationsState.ensureIcon(mEntry); + } + // This might trigger us to bind again, but it gives an easy way to only + // load the icon once its needed, so its probably worth it. + setIcon(mEntry.icon); + } + }); + } + super.onBindViewHolder(holder); + holder.itemView.findViewById(R.id.appendix).setVisibility(View.GONE); + } + + public void reuse() { + setState(); + notifyChanged(); + } + + public AppEntry getEntry() { + return mEntry; + } + + private void setState() { + setTitle(mEntry.label); + setSummary(getDomainsSummary(mEntry.info.packageName)); + } + + private CharSequence getDomainsSummary(String packageName) { + // If the user has explicitly said "no" for this package, that's the + // string we should show. + int domainStatus = + mPm.getIntentVerificationStatusAsUser(packageName, UserHandle.myUserId()); + if (domainStatus == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { + return getContext().getText(R.string.domain_urls_summary_none); + } + // Otherwise, ask package manager for the domains for this package, + // and show the first one (or none if there aren't any). + final ArraySet result = Utils.getHandledDomains(mPm, packageName); + if (result.isEmpty()) { + return getContext().getText(R.string.domain_urls_summary_none); + } else if (result.size() == 1) { + return getContext().getString(R.string.domain_urls_summary_one, result.valueAt(0)); + } else { + return getContext().getString(R.string.domain_urls_summary_some, result.valueAt(0)); + } + } +} diff --git a/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceController.java b/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceController.java new file mode 100644 index 00000000000..384a5cf1c00 --- /dev/null +++ b/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceController.java @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2018 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.managedomainurls; + +import android.app.Application; +import android.content.Context; +import android.text.TextUtils; +import android.util.ArrayMap; + +import com.android.settings.R; +import com.android.settings.applications.AppInfoBase; +import com.android.settings.applications.AppLaunchSettings; +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.applications.ApplicationsState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; + +import java.util.ArrayList; +import java.util.Map; + +import androidx.preference.Preference; +import androidx.preference.PreferenceGroup; +import androidx.preference.PreferenceScreen; + +public class DomainAppPreferenceController extends BasePreferenceController implements + ApplicationsState.Callbacks { + + // constant value that can be used to check return code from sub activity. + private static final int INSTALLED_APP_DETAILS = 1; + + private int mMetricsCategory; + private ApplicationsState mApplicationsState; + private ApplicationsState.Session mSession; + private ManageDomainUrls mFragment; + private PreferenceGroup mDomainAppList; + private Map mPreferenceCache; + + public DomainAppPreferenceController(Context context, String key) { + super(context, key); + mApplicationsState = ApplicationsState.getInstance( + (Application) mContext.getApplicationContext()); + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mDomainAppList = (PreferenceGroup) screen.findPreference(getPreferenceKey()); + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (preference instanceof DomainAppPreference) { + ApplicationsState.AppEntry entry = ((DomainAppPreference) preference).getEntry(); + AppInfoBase.startAppInfoFragment(AppLaunchSettings.class, R.string.auto_launch_label, + entry.info.packageName, entry.info.uid, mFragment, + INSTALLED_APP_DETAILS, mMetricsCategory); + return true; + } + return false; + } + + public void setFragment(ManageDomainUrls fragment) { + mFragment = fragment; + mMetricsCategory = fragment.getMetricsCategory(); + mSession = mApplicationsState.newSession(this, mFragment.getLifecycle()); + } + + @Override + public void onRunningStateChanged(boolean running) { + } + + @Override + public void onPackageListChanged() { + } + + @Override + public void onRebuildComplete(ArrayList apps) { + if (mContext == null) { + return; + } + rebuildAppList(mDomainAppList, apps); + } + + @Override + public void onPackageIconChanged() { + } + + @Override + public void onPackageSizeChanged(String packageName) { + } + + @Override + public void onAllSizesComputed() { + } + + @Override + public void onLauncherInfoChanged() { + } + + @Override + public void onLoadEntriesCompleted() { + rebuild(); + } + + private void cacheAllPrefs(PreferenceGroup group) { + mPreferenceCache = new ArrayMap(); + final int count = group.getPreferenceCount(); + for (int i = 0; i < count; i++) { + Preference p = group.getPreference(i); + if (TextUtils.isEmpty(p.getKey())) { + continue; + } + mPreferenceCache.put(p.getKey(), p); + } + } + + private Preference getCachedPreference(String key) { + return mPreferenceCache != null ? mPreferenceCache.remove(key) : null; + } + + private void removeCachedPrefs(PreferenceGroup group) { + for (Preference p : mPreferenceCache.values()) { + group.removePreference(p); + } + mPreferenceCache = null; + } + + private void rebuild() { + final ArrayList apps = mSession.rebuild( + ApplicationsState.FILTER_WITH_DOMAIN_URLS, ApplicationsState.ALPHA_COMPARATOR); + if (apps != null) { + onRebuildComplete(apps); + } + } + + private void rebuildAppList(PreferenceGroup group, ArrayList apps) { + cacheAllPrefs(group); + final int size = apps.size(); + for (int i = 0; i < size; i++) { + AppEntry entry = apps.get(i); + String key = entry.info.packageName + "|" + entry.info.uid; + DomainAppPreference preference = (DomainAppPreference) getCachedPreference(key); + if (preference == null) { + preference = new DomainAppPreference(group.getContext(), mApplicationsState, entry); + preference.setKey(key); + group.addPreference(preference); + } else { + preference.reuse(); + } + preference.setOrder(i); + } + removeCachedPrefs(group); + } +} diff --git a/src/com/android/settings/applications/managedomainurls/InstantAppAccountPreferenceController.java b/src/com/android/settings/applications/managedomainurls/InstantAppAccountPreferenceController.java new file mode 100644 index 00000000000..36fd788a16c --- /dev/null +++ b/src/com/android/settings/applications/managedomainurls/InstantAppAccountPreferenceController.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2018 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.managedomainurls; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; + +import com.android.settings.core.BasePreferenceController; + +import androidx.preference.Preference; + +public class InstantAppAccountPreferenceController extends BasePreferenceController { + + private Intent mLaunchIntent; + + public InstantAppAccountPreferenceController(Context context, String key) { + super(context, key); + initAppSettingsIntent(); + } + + @Override + public int getAvailabilityStatus() { + if (mLaunchIntent == null || WebActionCategoryController.isDisableWebActions(mContext)) { + return UNSUPPORTED_ON_DEVICE; + } else { + return AVAILABLE; + } + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (!getPreferenceKey().equals(preference.getKey())) { + return false; + } + // TODO: Make this button actually launch the account chooser. + if (mLaunchIntent != null) { + mContext.startActivity(mLaunchIntent); + } + return true; + } + + private void initAppSettingsIntent() { + // Determine whether we should show the instant apps account chooser setting + ComponentName instantAppSettingsComponent = + mContext.getPackageManager().getInstantAppResolverSettingsComponent(); + Intent instantAppSettingsIntent = null; + if (instantAppSettingsComponent != null) { + instantAppSettingsIntent = + new Intent().setComponent(instantAppSettingsComponent); + } + + if (instantAppSettingsIntent != null) { + mLaunchIntent = instantAppSettingsIntent; + } + } +} diff --git a/src/com/android/settings/applications/managedomainurls/InstantAppWebActionPreferenceController.java b/src/com/android/settings/applications/managedomainurls/InstantAppWebActionPreferenceController.java new file mode 100644 index 00000000000..77abfe71171 --- /dev/null +++ b/src/com/android/settings/applications/managedomainurls/InstantAppWebActionPreferenceController.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018 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.managedomainurls; + +import android.content.Context; +import android.provider.Settings; + +import com.android.settings.core.TogglePreferenceController; + +public class InstantAppWebActionPreferenceController extends TogglePreferenceController { + + public InstantAppWebActionPreferenceController(Context context, String key) { + super(context, key); + } + + @Override + public int getAvailabilityStatus() { + return WebActionCategoryController.isDisableWebActions(mContext) + ? UNSUPPORTED_ON_DEVICE + : AVAILABLE; + } + + public boolean isChecked() { + return Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.INSTANT_APPS_ENABLED, 1) == 1; + } + + public boolean setChecked(boolean isChecked) { + return Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.INSTANT_APPS_ENABLED, isChecked ? 1 : 0); + } +} diff --git a/src/com/android/settings/applications/managedomainurls/ManageDomainUrls.java b/src/com/android/settings/applications/managedomainurls/ManageDomainUrls.java new file mode 100644 index 00000000000..16f954a357f --- /dev/null +++ b/src/com/android/settings/applications/managedomainurls/ManageDomainUrls.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 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.managedomainurls; + +import static com.android.settingslib.search.SearchIndexable.MOBILE; + +import android.content.Context; +import android.provider.SearchIndexableResource; + +import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.settings.R; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.search.BaseSearchIndexProvider; +import com.android.settings.search.Indexable; +import com.android.settingslib.search.SearchIndexable; + +import java.util.ArrayList; +import java.util.List; + +/** + * Activity to manage how Android handles URL resolution. Includes both per-app + * handling as well as system handling for Web Actions. + */ +@SearchIndexable(forTarget = MOBILE) +public class ManageDomainUrls extends DashboardFragment { + + private static final String TAG = "ManageDomainUrls"; + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + use(DomainAppPreferenceController.class).setFragment(this); + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.manage_domain_url_settings; + } + + @Override + public int getMetricsCategory() { + return MetricsEvent.MANAGE_DOMAIN_URLS; + } + + public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final ArrayList result = new ArrayList<>(); + + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.manage_domain_url_settings; + result.add(sir); + return result; + } + }; +} diff --git a/src/com/android/settings/applications/managedomainurls/WebActionCategoryController.java b/src/com/android/settings/applications/managedomainurls/WebActionCategoryController.java new file mode 100644 index 00000000000..5aa57db75c4 --- /dev/null +++ b/src/com/android/settings/applications/managedomainurls/WebActionCategoryController.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 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.managedomainurls; + +import android.content.Context; +import android.provider.Settings; + +import com.android.settings.core.BasePreferenceController; + +public class WebActionCategoryController extends BasePreferenceController { + + public WebActionCategoryController(Context context, String key) { + super(context, key); + } + + @Override + public int getAvailabilityStatus() { + return isDisableWebActions(mContext) ? UNSUPPORTED_ON_DEVICE : AVAILABLE; + } + + public static boolean isDisableWebActions(Context context) { + return Settings.Global.getInt(context.getContentResolver(), + Settings.Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0; + } +} diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java index aab3512cf15..2a60c16feef 100644 --- a/src/com/android/settings/core/gateway/SettingsGateway.java +++ b/src/com/android/settings/core/gateway/SettingsGateway.java @@ -36,7 +36,6 @@ import com.android.settings.accounts.ManagedProfileSettings; import com.android.settings.applications.AppAndNotificationDashboardFragment; import com.android.settings.applications.DefaultAppSettings; import com.android.settings.applications.DirectoryAccessDetails; -import com.android.settings.applications.ManageDomainUrls; import com.android.settings.applications.ProcessStatsSummary; import com.android.settings.applications.ProcessStatsUi; import com.android.settings.applications.UsageAccessDetails; @@ -50,6 +49,7 @@ import com.android.settings.applications.appinfo.WriteSettingsDetails; import com.android.settings.applications.appops.BackgroundCheckSummary; import com.android.settings.applications.assist.ManageAssist; import com.android.settings.applications.manageapplications.ManageApplications; +import com.android.settings.applications.managedomainurls.ManageDomainUrls; import com.android.settings.backup.PrivacySettings; import com.android.settings.backup.ToggleBackupSettingFragment; import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment; @@ -79,9 +79,9 @@ import com.android.settings.gestures.AssistGestureSettings; import com.android.settings.gestures.DoubleTapPowerSettings; import com.android.settings.gestures.DoubleTapScreenSettings; import com.android.settings.gestures.DoubleTwistGestureSettings; -import com.android.settings.gestures.SwipeUpGestureSettings; import com.android.settings.gestures.PickupGestureSettings; import com.android.settings.gestures.SwipeToNotificationSettings; +import com.android.settings.gestures.SwipeUpGestureSettings; import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment; import com.android.settings.inputmethod.KeyboardLayoutPickerFragment; import com.android.settings.inputmethod.PhysicalKeyboardFragment; @@ -106,10 +106,8 @@ import com.android.settings.notification.NotificationStation; import com.android.settings.notification.SoundSettings; import com.android.settings.notification.ZenAccessSettings; import com.android.settings.notification.ZenModeAutomationSettings; -import com.android.settings.notification.ZenModeMsgEventReminderSettings; import com.android.settings.notification.ZenModeBlockedEffectsSettings; import com.android.settings.notification.ZenModeEventRuleSettings; -import com.android.settings.notification.ZenModeRestrictNotificationsSettings; import com.android.settings.notification.ZenModeScheduleRuleSettings; import com.android.settings.notification.ZenModeSettings; import com.android.settings.password.ChooseLockPassword; diff --git a/tests/robotests/assets/grandfather_not_implementing_indexable b/tests/robotests/assets/grandfather_not_implementing_indexable index 442df76f909..393fe61c490 100644 --- a/tests/robotests/assets/grandfather_not_implementing_indexable +++ b/tests/robotests/assets/grandfather_not_implementing_indexable @@ -13,7 +13,6 @@ com.android.settings.applications.VrListenerSettings com.android.settings.datausage.DataSaverSummary com.android.settings.datausage.AppDataUsage com.android.settings.accessibility.FontSizePreferenceFragmentForSetupWizard -com.android.settings.applications.ManageDomainUrls com.android.settings.applications.appinfo.WriteSettingsDetails com.android.settings.applications.ProcessStatsSummary com.android.settings.users.RestrictedProfileSettings diff --git a/tests/robotests/src/com/android/settings/applications/ManageDomainUrlsTest.java b/tests/robotests/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceControllerTest.java similarity index 86% rename from tests/robotests/src/com/android/settings/applications/ManageDomainUrlsTest.java rename to tests/robotests/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceControllerTest.java index 217a352b1fd..312fb1f4bc4 100644 --- a/tests/robotests/src/com/android/settings/applications/ManageDomainUrlsTest.java +++ b/tests/robotests/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceControllerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * Copyright (C) 2018 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.settings.applications; +package com.android.settings.applications.managedomainurls; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.mock; @@ -26,7 +26,6 @@ import android.content.pm.ApplicationInfo; import android.graphics.drawable.Drawable; import android.view.View; import android.widget.ProgressBar; -import androidx.preference.PreferenceViewHolder; import com.android.settings.R; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -39,8 +38,10 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; +import androidx.preference.PreferenceViewHolder; + @RunWith(SettingsRobolectricTestRunner.class) -public class ManageDomainUrlsTest { +public class DomainAppPreferenceControllerTest { @Mock private ApplicationsState.AppEntry mAppEntry; @@ -56,8 +57,7 @@ public class ManageDomainUrlsTest { public void domainAppPreferenceShouldUseAppPreferenceLayout() { mAppEntry.info = new ApplicationInfo(); mAppEntry.info.packageName = "com.android.settings.test"; - final ManageDomainUrls.DomainAppPreference pref = - new ManageDomainUrls.DomainAppPreference(mContext, null, mAppEntry); + final DomainAppPreference pref = new DomainAppPreference(mContext, null, mAppEntry); assertThat(pref.getLayoutResource()).isEqualTo(R.layout.preference_app); } @@ -67,8 +67,7 @@ public class ManageDomainUrlsTest { mAppEntry.info = new ApplicationInfo(); mAppEntry.info.packageName = "com.android.settings.test"; mAppEntry.icon = mock(Drawable.class); - final ManageDomainUrls.DomainAppPreference pref = - new ManageDomainUrls.DomainAppPreference(mContext, null, mAppEntry); + final DomainAppPreference pref = new DomainAppPreference(mContext, null, mAppEntry); final View holderView = mock(View.class); final View appendixView = mock(View.class); when(holderView.findViewById(R.id.summary_container)).thenReturn(mock(View.class)); diff --git a/tests/robotests/src/com/android/settings/applications/managedomainurls/InstantAppAccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/managedomainurls/InstantAppAccountPreferenceControllerTest.java new file mode 100644 index 00000000000..fc789bf18da --- /dev/null +++ b/tests/robotests/src/com/android/settings/applications/managedomainurls/InstantAppAccountPreferenceControllerTest.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2018 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.managedomainurls; + +import static android.provider.Settings.Global.ENABLE_EPHEMERAL_FEATURE; +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.ComponentName; +import android.content.ContentResolver; +import android.content.Context; +import android.content.pm.PackageManager; +import android.provider.Settings; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.After; +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; + +@RunWith(SettingsRobolectricTestRunner.class) +public class InstantAppAccountPreferenceControllerTest { + + private static final String PREF_KEY = "instant_app_account_pref"; + + @Mock + private ComponentName mComponentName; + @Mock + private PackageManager mPackageManager; + + private Context mContext; + private ContentResolver mContentResolver; + private int mEnableEphemeralFeature; + private InstantAppAccountPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + mContentResolver = mContext.getContentResolver(); + mEnableEphemeralFeature = Settings.Secure.getInt(mContentResolver, + ENABLE_EPHEMERAL_FEATURE, 1); + } + + @After + public void tearDown() { + Settings.Secure.putInt(mContentResolver, ENABLE_EPHEMERAL_FEATURE, + mEnableEphemeralFeature); + } + + @Test + public void testGetAvailabilityStatus_nullAppSettingsComponent() { + when(mPackageManager.getInstantAppResolverSettingsComponent()).thenReturn(null); + mController = new InstantAppAccountPreferenceController(mContext, PREF_KEY); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + public void testGetAvailabilityStatus_enableWebActiions() { + when(mPackageManager.getInstantAppResolverSettingsComponent()).thenReturn(mComponentName); + mController = new InstantAppAccountPreferenceController(mContext, PREF_KEY); + Settings.Secure.putInt(mContentResolver, ENABLE_EPHEMERAL_FEATURE, 1); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + public void testGetAvailabilityStatus_disableWebActions() { + when(mPackageManager.getInstantAppResolverSettingsComponent()).thenReturn(mComponentName); + mController = new InstantAppAccountPreferenceController(mContext, PREF_KEY); + Settings.Secure.putInt(mContentResolver, ENABLE_EPHEMERAL_FEATURE, 0); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + } +} diff --git a/tests/robotests/src/com/android/settings/applications/managedomainurls/InstantAppWebActionPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/managedomainurls/InstantAppWebActionPreferenceControllerTest.java new file mode 100644 index 00000000000..8d1b584f7e1 --- /dev/null +++ b/tests/robotests/src/com/android/settings/applications/managedomainurls/InstantAppWebActionPreferenceControllerTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2018 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.managedomainurls; + +import static android.provider.Settings.Global.ENABLE_EPHEMERAL_FEATURE; +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; + +import android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +import androidx.preference.SwitchPreference; + +@RunWith(SettingsRobolectricTestRunner.class) +public class InstantAppWebActionPreferenceControllerTest { + private static final String PREF_KEY = "instant_app_web_action_toggle"; + private static final String KEY_INSTANT_APPS_ENABLED = Settings.Secure.INSTANT_APPS_ENABLED; + + private Context mContext; + private ContentResolver mContentResolver; + private int mEnableEphemeralFeature; + private InstantAppWebActionPreferenceController mController; + private SwitchPreference mSwitchPreference; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + mContentResolver = mContext.getContentResolver(); + mController = new InstantAppWebActionPreferenceController(mContext, PREF_KEY); + mSwitchPreference = new SwitchPreference(mContext); + mEnableEphemeralFeature = Settings.Secure.getInt(mContentResolver, + ENABLE_EPHEMERAL_FEATURE, 1); + } + + @After + public void tearDown() { + Settings.Secure.putInt(mContentResolver, ENABLE_EPHEMERAL_FEATURE, + mEnableEphemeralFeature); + } + + @Test + public void testGetAvailabilityStatus_enableWebActions() { + Settings.Secure.putInt(mContentResolver, ENABLE_EPHEMERAL_FEATURE, 1); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + public void testGetAvailabilityStatus_disableWebActions() { + Settings.Secure.putInt(mContentResolver, ENABLE_EPHEMERAL_FEATURE, 0); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + public void onPreferenceChange_enable() { + mController.onPreferenceChange(mSwitchPreference, true); + + assertThat(Settings.Secure.getInt(mContentResolver, KEY_INSTANT_APPS_ENABLED, -1)) + .isEqualTo(1); + } + + @Test + public void onPreferenceChange_disable() { + mController.onPreferenceChange(mSwitchPreference, false); + + assertThat(Settings.Secure.getInt(mContentResolver, KEY_INSTANT_APPS_ENABLED, -1)) + .isEqualTo(0); + } +}