Add a new special app access screen for long background tasks.

This new screen shows apps that hold the new RUN_LONG_JOBS permission.

Also add a reference to this screen in an app's info page under the
"Advanced" section for apps that have requested this permission.

Bug: 255821578
Test: atest AppFilterRegistryTest
Test: make -j RunSettingsRoboTests \
ROBOTTEST_FILTER="LongBackgroundTasksDetailsTest|
LongBackgroundTasksDetailsPreferenceControllerTest"
Test: visually via the Settings page

Change-Id: Idc498e52d29abc6df757c35e8bc91f00de92ba4a
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index b95c9b0..e394e45 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -430,6 +430,11 @@
         }
     }
 
+    /** Actviity to manage apps with {@link android.Manifest.permission#RUN_LONG_JOBS} */
+    public static class LongBackgroundTasksActivity extends SettingsActivity { /* empty */ }
+    /** App specific version of {@link LongBackgroundTasksActivity} */
+    public static class LongBackgroundTasksAppActivity extends SettingsActivity { /* empty */ }
+
     /**
      * Activity for BugReportHandlerPicker.
      */
diff --git a/src/com/android/settings/applications/AppStateLongBackgroundTasksBridge.java b/src/com/android/settings/applications/AppStateLongBackgroundTasksBridge.java
new file mode 100644
index 0000000..d286c5e
--- /dev/null
+++ b/src/com/android/settings/applications/AppStateLongBackgroundTasksBridge.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2022 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.Manifest;
+import android.app.AppGlobals;
+import android.app.job.JobScheduler;
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+import com.android.settingslib.applications.ApplicationsState;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+import com.android.settingslib.applications.ApplicationsState.AppFilter;
+
+import libcore.util.EmptyArray;
+
+import java.util.List;
+
+/**
+ * Connects app op info to the ApplicationsState. Extends {@link AppStateAppOpsBridge} to tailor
+ * to the semantics of {@link Manifest.permission#RUN_LONG_JOBS}.
+ * Also provides app filters that can use the info.
+ */
+public class AppStateLongBackgroundTasksBridge extends AppStateBaseBridge {
+    private static final String PERMISSION = Manifest.permission.RUN_LONG_JOBS;
+    private static final String TAG = "LongBackgroundTasksBridge";
+
+    @VisibleForTesting
+    JobScheduler mJobScheduler;
+    @VisibleForTesting
+    String[] mRequesterPackages;
+
+    public AppStateLongBackgroundTasksBridge(Context context, ApplicationsState appState,
+            Callback callback) {
+        super(appState, callback);
+
+        mJobScheduler = context.getSystemService(JobScheduler.class);
+        final IPackageManager iPm = AppGlobals.getPackageManager();
+        try {
+            mRequesterPackages = iPm.getAppOpPermissionPackages(PERMISSION, context.getUserId());
+        } catch (RemoteException re) {
+            Log.e(TAG, "Cannot reach package manager", re);
+            mRequesterPackages = EmptyArray.STRING;
+        }
+    }
+
+    /**
+     * Returns information regarding {@link Manifest.permission#RUN_LONG_JOBS} for the given
+     * package and uid.
+     */
+    public LongBackgroundTasksState createPermissionState(String packageName, int uid) {
+        final int userId = UserHandle.getUserId(uid);
+
+        final boolean permissionRequested = ArrayUtils.contains(mRequesterPackages, packageName);
+        final boolean permissionGranted = mJobScheduler.hasRunLongJobsPermission(packageName,
+                userId);
+        return new LongBackgroundTasksState(permissionRequested, permissionGranted);
+    }
+
+    @Override
+    protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
+        app.extraInfo = createPermissionState(pkg, uid);
+    }
+
+    @Override
+    protected void loadAllExtraInfo() {
+        final List<AppEntry> allApps = mAppSession.getAllApps();
+        for (int i = 0; i < allApps.size(); i++) {
+            final AppEntry currentEntry = allApps.get(i);
+            updateExtraInfo(currentEntry, currentEntry.info.packageName, currentEntry.info.uid);
+        }
+    }
+
+    public static final AppFilter FILTER_LONG_JOBS_APPS = new AppFilter() {
+
+        @Override
+        public void init() {
+        }
+
+        @Override
+        public boolean filterApp(AppEntry info) {
+            if (info.extraInfo instanceof LongBackgroundTasksState) {
+                final LongBackgroundTasksState state = (LongBackgroundTasksState) info.extraInfo;
+                return state.shouldBeVisible();
+            }
+            return false;
+        }
+    };
+
+    /**
+     * Class to denote the state of an app regarding
+     * {@link Manifest.permission#RUN_LONG_JOBS}.
+     */
+    public static class LongBackgroundTasksState {
+        private boolean mPermissionRequested;
+        private boolean mPermissionGranted;
+
+        LongBackgroundTasksState(boolean permissionRequested, boolean permissionGranted) {
+            mPermissionRequested = permissionRequested;
+            mPermissionGranted = permissionGranted;
+        }
+
+        /** Should the app associated with this state appear on the Settings screen */
+        public boolean shouldBeVisible() {
+            return mPermissionRequested;
+        }
+
+        /** Is the permission granted to the app associated with this state */
+        public boolean isAllowed() {
+            return mPermissionGranted;
+        }
+    }
+}
diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
index 7049b56..4a00260 100644
--- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
+++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java
@@ -215,10 +215,15 @@
         alarmsAndReminders.setPackageName(packageName);
         alarmsAndReminders.setParentFragment(this);
 
+        final LongBackgroundTasksDetailsPreferenceController longBackgroundTasks =
+                use(LongBackgroundTasksDetailsPreferenceController.class);
+        longBackgroundTasks.setPackageName(packageName);
+        longBackgroundTasks.setParentFragment(this);
+
         final AdvancedAppInfoPreferenceCategoryController advancedAppInfo =
                 use(AdvancedAppInfoPreferenceCategoryController.class);
         advancedAppInfo.setChildren(Arrays.asList(writeSystemSettings, drawOverlay, pip,
-                externalSource, acrossProfiles, alarmsAndReminders));
+                externalSource, acrossProfiles, alarmsAndReminders, longBackgroundTasks));
         advancedAppInfo.setAppEntry(mAppEntry);
 
         final AppLocalePreferenceController appLocale =
diff --git a/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetails.java b/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetails.java
new file mode 100644
index 0000000..1e5d11a
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetails.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settings.applications.appinfo;
+
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.Activity.RESULT_OK;
+
+import android.app.AppOpsManager;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.appcompat.app.AlertDialog;
+import androidx.preference.Preference;
+import androidx.preference.Preference.OnPreferenceChangeListener;
+
+import com.android.settings.R;
+import com.android.settings.Settings;
+import com.android.settings.applications.AppInfoWithHeader;
+import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
+import com.android.settingslib.RestrictedSwitchPreference;
+import com.android.settingslib.applications.ApplicationsState.AppEntry;
+
+/**
+ * App specific activity to show details about
+ * {@link android.Manifest.permission#RUN_LONG_JOBS}.
+ */
+public class LongBackgroundTasksDetails extends AppInfoWithHeader
+        implements OnPreferenceChangeListener {
+
+    private static final String KEY_SWITCH = "long_background_tasks_switch";
+    private static final String UNCOMMITTED_STATE_KEY = "uncommitted_state";
+
+    private AppStateLongBackgroundTasksBridge mAppBridge;
+    private AppOpsManager mAppOpsManager;
+    private RestrictedSwitchPreference mSwitchPref;
+    private AppStateLongBackgroundTasksBridge.LongBackgroundTasksState mPermissionState;
+    private volatile Boolean mUncommittedState;
+
+    /**
+     * Returns the string that states whether the app has access to
+     * {@link android.Manifest.permission#RUN_LONG_JOBS}.
+     */
+    public static CharSequence getSummary(Context context, AppEntry entry) {
+        final AppStateLongBackgroundTasksBridge.LongBackgroundTasksState state =
+                new AppStateLongBackgroundTasksBridge(context, /*appState=*/null,
+                        /*callback=*/null).createPermissionState(entry.info.packageName,
+                        entry.info.uid);
+
+        return context.getString(state.isAllowed() ? R.string.app_permission_summary_allowed
+                : R.string.app_permission_summary_not_allowed);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final Context context = getActivity();
+        mAppBridge = new AppStateLongBackgroundTasksBridge(context, mState, /*callback=*/null);
+        mAppOpsManager = context.getSystemService(AppOpsManager.class);
+
+        if (savedInstanceState != null) {
+            mUncommittedState = (Boolean) savedInstanceState.get(UNCOMMITTED_STATE_KEY);
+            if (mUncommittedState != null && isAppSpecific()) {
+                setResult(mUncommittedState ? RESULT_OK : RESULT_CANCELED);
+            }
+        }
+        addPreferencesFromResource(R.xml.long_background_tasks);
+        mSwitchPref = findPreference(KEY_SWITCH);
+        mSwitchPref.setOnPreferenceChangeListener(this);
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        if (mUncommittedState != null) {
+            outState.putObject(UNCOMMITTED_STATE_KEY, mUncommittedState);
+        }
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        if (preference == mSwitchPref) {
+            mUncommittedState = (Boolean) newValue;
+            if (isAppSpecific()) {
+                setResult(mUncommittedState ? RESULT_OK : RESULT_CANCELED);
+            }
+            refreshUi();
+            return true;
+        }
+        return false;
+    }
+
+    private void setCanRunLongJobs(boolean newState) {
+        final int uid = mPackageInfo.applicationInfo.uid;
+        mAppOpsManager.setUidMode(AppOpsManager.OPSTR_RUN_LONG_JOBS, uid,
+                newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED);
+    }
+
+    private void logPermissionChange(boolean newState, String packageName) {
+        mMetricsFeatureProvider.action(
+                mMetricsFeatureProvider.getAttribution(getActivity()),
+                SettingsEnums.ACTION_LONG_BACKGROUND_TASKS_TOGGLE,
+                getMetricsCategory(),
+                packageName,
+                newState ? 1 : 0);
+    }
+
+    private boolean isAppSpecific() {
+        return Settings.LongBackgroundTasksAppActivity.class.getName().equals(
+                getIntent().getComponent().getClassName());
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        if (getActivity().isChangingConfigurations()) {
+            return;
+        }
+        if (mPermissionState != null && mUncommittedState != null
+                && mUncommittedState != mPermissionState.isAllowed()) {
+            setCanRunLongJobs(mUncommittedState);
+            logPermissionChange(mUncommittedState, mPackageName);
+            mUncommittedState = null;
+        }
+    }
+
+    @Override
+    protected boolean refreshUi() {
+        if (mPackageInfo == null || mPackageInfo.applicationInfo == null) {
+            return false;
+        }
+        mPermissionState = mAppBridge.createPermissionState(mPackageName,
+                mPackageInfo.applicationInfo.uid);
+        mSwitchPref.setEnabled(mPermissionState.shouldBeVisible());
+        mSwitchPref.setChecked(
+                mUncommittedState != null ? mUncommittedState : mPermissionState.isAllowed());
+        return true;
+    }
+
+    @Override
+    protected AlertDialog createDialog(int id, int errorCode) {
+        return null;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.LONG_BACKGROUND_TASKS;
+    }
+}
diff --git a/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetailsPreferenceController.java b/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetailsPreferenceController.java
new file mode 100644
index 0000000..a41280b
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/LongBackgroundTasksDetailsPreferenceController.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.applications.appinfo;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
+
+/**
+ * Preference controller for
+ * {@link LongBackgroundTasksDetails} Settings fragment.
+ */
+public class LongBackgroundTasksDetailsPreferenceController extends
+        AppInfoPreferenceControllerBase {
+
+    private String mPackageName;
+
+    public LongBackgroundTasksDetailsPreferenceController(Context context, String key) {
+        super(context, key);
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return isCandidate() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        preference.setSummary(getPreferenceSummary());
+    }
+
+    @Override
+    protected Class<? extends SettingsPreferenceFragment> getDetailFragmentClass() {
+        return LongBackgroundTasksDetails.class;
+    }
+
+    @VisibleForTesting
+    CharSequence getPreferenceSummary() {
+        return LongBackgroundTasksDetails.getSummary(mContext, mParent.getAppEntry());
+    }
+
+    @VisibleForTesting
+    boolean isCandidate() {
+        final PackageInfo packageInfo = mParent.getPackageInfo();
+        if (packageInfo == null) {
+            return false;
+        }
+        final AppStateLongBackgroundTasksBridge.LongBackgroundTasksState appState =
+                new AppStateLongBackgroundTasksBridge(
+                        mContext, /*appState=*/null, /*callback=*/null)
+                        .createPermissionState(mPackageName, packageInfo.applicationInfo.uid);
+        return appState.shouldBeVisible();
+    }
+
+    void setPackageName(String packageName) {
+        mPackageName = packageName;
+    }
+}
diff --git a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
index 15cf8e7..b48bdbb 100644
--- a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
+++ b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java
@@ -23,6 +23,7 @@
 import com.android.settings.applications.AppStateAppBatteryUsageBridge;
 import com.android.settings.applications.AppStateInstallAppsBridge;
 import com.android.settings.applications.AppStateLocaleBridge;
+import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
 import com.android.settings.applications.AppStateManageExternalStorageBridge;
 import com.android.settings.applications.AppStateMediaManagementAppsBridge;
 import com.android.settings.applications.AppStateNotificationBridge;
@@ -61,6 +62,7 @@
                 FILTER_APPS_BATTERY_UNRESTRICTED,
                 FILTER_APPS_BATTERY_OPTIMIZED,
                 FILTER_APPS_BATTERY_RESTRICTED,
+                FILTER_LONG_BACKGROUND_TASKS,
             })
     @interface FilterType {}
 
@@ -89,8 +91,9 @@
     public static final int FILTER_APPS_BATTERY_UNRESTRICTED = 21;
     public static final int FILTER_APPS_BATTERY_OPTIMIZED = 22;
     public static final int FILTER_APPS_BATTERY_RESTRICTED = 23;
-    // Next id: 24. If you add an entry here, please change NUM_FILTER_ENTRIES.
-    private static final int NUM_FILTER_ENTRIES = 24;
+    public static final int FILTER_LONG_BACKGROUND_TASKS = 24;
+    // Next id: 25. If you add an entry here, please change NUM_FILTER_ENTRIES.
+    private static final int NUM_FILTER_ENTRIES = 25;
 
     private static AppFilterRegistry sRegistry;
 
@@ -242,6 +245,12 @@
                         AppStateAppBatteryUsageBridge.FILTER_BATTERY_RESTRICTED_APPS,
                         FILTER_APPS_BATTERY_RESTRICTED,
                         R.string.filter_battery_restricted_title);
+
+        // Apps that can run long background tasks
+        mFilters[FILTER_LONG_BACKGROUND_TASKS] = new AppFilterItem(
+                AppStateLongBackgroundTasksBridge.FILTER_LONG_JOBS_APPS,
+                FILTER_LONG_BACKGROUND_TASKS,
+                R.string.long_background_tasks_title);
     }
 
 
@@ -280,6 +289,8 @@
                 return FILTER_APPS_LOCALE;
             case ManageApplications.LIST_TYPE_BATTERY_OPTIMIZATION:
                 return FILTER_APPS_BATTERY_OPTIMIZED;
+            case ManageApplications.LIST_TYPE_LONG_BACKGROUND_TASKS:
+                return FILTER_LONG_BACKGROUND_TASKS;
             default:
                 return FILTER_APPS_ALL;
         }
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index a41230a..e129954 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -94,6 +94,7 @@
 import com.android.settings.Settings.ChangeWifiStateActivity;
 import com.android.settings.Settings.GamesStorageActivity;
 import com.android.settings.Settings.HighPowerApplicationsActivity;
+import com.android.settings.Settings.LongBackgroundTasksActivity;
 import com.android.settings.Settings.ManageExternalSourcesActivity;
 import com.android.settings.Settings.ManageExternalStorageActivity;
 import com.android.settings.Settings.MediaManagementAppsActivity;
@@ -112,6 +113,7 @@
 import com.android.settings.applications.AppStateBaseBridge;
 import com.android.settings.applications.AppStateInstallAppsBridge;
 import com.android.settings.applications.AppStateLocaleBridge;
+import com.android.settings.applications.AppStateLongBackgroundTasksBridge;
 import com.android.settings.applications.AppStateManageExternalStorageBridge;
 import com.android.settings.applications.AppStateMediaManagementAppsBridge;
 import com.android.settings.applications.AppStateNotificationBridge;
@@ -128,6 +130,7 @@
 import com.android.settings.applications.appinfo.AppLocaleDetails;
 import com.android.settings.applications.appinfo.DrawOverlayDetails;
 import com.android.settings.applications.appinfo.ExternalSourcesDetails;
+import com.android.settings.applications.appinfo.LongBackgroundTasksDetails;
 import com.android.settings.applications.appinfo.ManageExternalStorageDetails;
 import com.android.settings.applications.appinfo.MediaManagementAppsDetails;
 import com.android.settings.applications.appinfo.WriteSettingsDetails;
@@ -256,6 +259,7 @@
     public static final int LIST_TYPE_MEDIA_MANAGEMENT_APPS = 13;
     public static final int LIST_TYPE_APPS_LOCALE = 14;
     public static final int LIST_TYPE_BATTERY_OPTIMIZATION = 15;
+    public static final int LIST_TYPE_LONG_BACKGROUND_TASKS = 16;
 
     // List types that should show instant apps.
     public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
@@ -402,6 +406,8 @@
             mListType = LIST_TYPE_APPS_LOCALE;
         } else if (className.equals(AppBatteryUsageActivity.class.getName())) {
             mListType = LIST_TYPE_BATTERY_OPTIMIZATION;
+        } else if (className.equals(LongBackgroundTasksActivity.class.getName())) {
+            mListType = LIST_TYPE_LONG_BACKGROUND_TASKS;
         } else {
             mListType = LIST_TYPE_MAIN;
         }
@@ -598,6 +604,8 @@
                 return SettingsEnums.APPS_LOCALE_LIST;
             case LIST_TYPE_BATTERY_OPTIMIZATION:
                 return SettingsEnums.BATTERY_OPTIMIZED_APPS_LIST;
+            case LIST_TYPE_LONG_BACKGROUND_TASKS:
+                return SettingsEnums.LONG_BACKGROUND_TASKS;
             default:
                 return SettingsEnums.PAGE_UNKNOWN;
         }
@@ -735,6 +743,10 @@
                         getActivity(), this, mCurrentPkgName,
                         UserHandle.getUserHandleForUid(mCurrentUid));
                 break;
+            case LIST_TYPE_LONG_BACKGROUND_TASKS:
+                startAppInfoFragment(LongBackgroundTasksDetails.class,
+                        R.string.long_background_tasks_label);
+                break;
             // TODO: Figure out if there is a way where we can spin up the profile's settings
             // process ahead of time, to avoid a long load of data when user clicks on a managed
             // app. Maybe when they load the list of apps that contains managed profile apps.
@@ -828,6 +840,8 @@
                 return R.string.help_uri_alarms_and_reminders;
             case LIST_TYPE_MEDIA_MANAGEMENT_APPS:
                 return R.string.help_uri_media_management_apps;
+            case LIST_TYPE_LONG_BACKGROUND_TASKS:
+                return R.string.help_uri_long_background_tasks;
             default:
             case LIST_TYPE_MAIN:
                 return R.string.help_uri_apps;
@@ -1030,6 +1044,8 @@
             screenTitle = R.string.app_locales_picker_menu_title;
         } else if (className.equals(AppBatteryUsageActivity.class.getName())) {
             screenTitle = R.string.app_battery_usage_title;
+        } else if (className.equals(LongBackgroundTasksActivity.class.getName())) {
+            screenTitle = R.string.long_background_tasks_title;
         } else {
             if (screenTitle == -1) {
                 screenTitle = R.string.all_apps;
@@ -1233,6 +1249,8 @@
                         mManageApplications.mUserManager);
             } else if (mManageApplications.mListType == LIST_TYPE_BATTERY_OPTIMIZATION) {
                 mExtraInfoBridge = new AppStateAppBatteryUsageBridge(mContext, mState, this);
+            } else if (mManageApplications.mListType == LIST_TYPE_LONG_BACKGROUND_TASKS) {
+                mExtraInfoBridge = new AppStateLongBackgroundTasksBridge(mContext, mState, this);
             } else {
                 mExtraInfoBridge = null;
             }
@@ -1762,6 +1780,9 @@
                 case LIST_TYPE_BATTERY_OPTIMIZATION:
                     holder.setSummary(null);
                     break;
+                case LIST_TYPE_LONG_BACKGROUND_TASKS:
+                    holder.setSummary(LongBackgroundTasksDetails.getSummary(mContext, entry));
+                    break;
                 default:
                     holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);
                     break;
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index b55b024..7904fdb 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -48,6 +48,7 @@
 import com.android.settings.applications.appinfo.AppLocaleDetails;
 import com.android.settings.applications.appinfo.DrawOverlayDetails;
 import com.android.settings.applications.appinfo.ExternalSourcesDetails;
+import com.android.settings.applications.appinfo.LongBackgroundTasksDetails;
 import com.android.settings.applications.appinfo.ManageExternalStorageDetails;
 import com.android.settings.applications.appinfo.MediaManagementAppsDetails;
 import com.android.settings.applications.appinfo.WriteSettingsDetails;
@@ -357,7 +358,8 @@
             TurnScreenOnSettings.class.getName(),
             TurnScreenOnDetails.class.getName(),
             NfcAndPaymentFragment.class.getName(),
-            ColorAndMotionFragment.class.getName()
+            ColorAndMotionFragment.class.getName(),
+            LongBackgroundTasksDetails.class.getName()
     };
 
     public static final String[] SETTINGS_FOR_RESTRICTED = {