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
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a21d056..5fbecc3 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -1070,7 +1070,7 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
-                       android:value="com.android.settings.applications.ManageDomainUrls" />
+                       android:value="com.android.settings.applications.managedomainurls.ManageDomainUrls" />
         </activity>
 
         <activity android:name="Settings$MemorySettingsActivity"
diff --git a/res/xml/app_default_settings.xml b/res/xml/app_default_settings.xml
index da4a33a..3b7c80b 100644
--- a/res/xml/app_default_settings.xml
+++ b/res/xml/app_default_settings.xml
@@ -76,7 +76,7 @@
     <com.android.settings.widget.AppPreference
         android:key="domain_urls"
         android:title="@string/domain_urls_title"
-        android:fragment="com.android.settings.applications.ManageDomainUrls"
+        android:fragment="com.android.settings.applications.managedomainurls.ManageDomainUrls"
         settings:keywords="@string/keywords_default_links"/>
 
     <com.android.settings.widget.WorkOnlyCategory
diff --git a/res/xml/manage_domain_url_settings.xml b/res/xml/manage_domain_url_settings.xml
index e4e4e47..e820e78 100644
--- a/res/xml/manage_domain_url_settings.xml
+++ b/res/xml/manage_domain_url_settings.xml
@@ -17,4 +17,27 @@
 
 <PreferenceScreen
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:title="@string/domain_urls_title" />
+    xmlns:settings="http://schemas.android.com/apk/res-auto"
+    android:title="@string/domain_urls_title"
+    android:key="manage_domain_url_screen">
+
+    <PreferenceCategory
+        android:key="web_action_category"
+        android:title="@string/web_action_section_title"
+        settings:controller="com.android.settings.applications.managedomainurls.WebActionCategoryController">
+        <SwitchPreference
+            android:key="instant_app_web_action_toggle"
+            android:title="@string/web_action_enable_title"
+            android:summary="@string/web_action_enable_summary"
+            settings:controller="com.android.settings.applications.managedomainurls.InstantAppWebActionPreferenceController" />
+        <Preference
+            android:key="instant_app_web_action_pref"
+            android:title="@string/instant_apps_settings"
+            settings:controller="com.android.settings.applications.managedomainurls.InstantAppAccountPreferenceController" />
+    </PreferenceCategory>
+
+    <PreferenceCategory
+        android:key="installed_apps_web_action"
+        android:title="@string/domain_url_section_title"
+        settings:controller="com.android.settings.applications.managedomainurls.DomainAppPreferenceController" />
+</PreferenceScreen>
\ 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 e47792d..0000000
--- 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<AppEntry> 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<AppEntry> apps = mSession.rebuild(
-                ApplicationsState.FILTER_WITH_DOMAIN_URLS, ApplicationsState.ALPHA_COMPARATOR);
-        if (apps != null) {
-            onRebuildComplete(apps);
-        }
-    }
-
-    private void rebuildAppList(PreferenceGroup group, ArrayList<AppEntry> 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<String> 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 0000000..e1f1e92
--- /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<String> 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 0000000..384a5cf
--- /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<String, Preference> 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<AppEntry> 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<AppEntry> apps = mSession.rebuild(
+                ApplicationsState.FILTER_WITH_DOMAIN_URLS, ApplicationsState.ALPHA_COMPARATOR);
+        if (apps != null) {
+            onRebuildComplete(apps);
+        }
+    }
+
+    private void rebuildAppList(PreferenceGroup group, ArrayList<AppEntry> 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 0000000..36fd788
--- /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 0000000..77abfe7
--- /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 0000000..16f954a
--- /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<SearchIndexableResource> getXmlResourcesToIndex(Context context,
+                        boolean enabled) {
+                    final ArrayList<SearchIndexableResource> 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 0000000..5aa57db
--- /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 aab3512..2a60c16 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.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.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.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.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 442df76..393fe61 100644
--- a/tests/robotests/assets/grandfather_not_implementing_indexable
+++ b/tests/robotests/assets/grandfather_not_implementing_indexable
@@ -13,7 +13,6 @@
 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 85%
rename from tests/robotests/src/com/android/settings/applications/ManageDomainUrlsTest.java
rename to tests/robotests/src/com/android/settings/applications/managedomainurls/DomainAppPreferenceControllerTest.java
index 217a352..312fb1f 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.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.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 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 @@
         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 0000000..fc789bf
--- /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 0000000..8d1b584
--- /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);
+    }
+}