Have a setting in Developer Options to choose bug report handler

- This setting let user determines which app handles the Bug Report
shortcut on device.

BUG:143017534
Test: make -j56 RunSettingsRoboTests
Test: Ensure bug report handler setting shows correct handler apps.
Change-Id: I6160dadcd048e6c79f422e58fcd8defa04f991bb
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index e203699..46992ef 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -169,6 +169,10 @@
     public static class WifiCallingDisclaimerActivity extends SettingsActivity { /* empty */ }
     public static class MobileNetworkListActivity extends SettingsActivity {}
     public static class GlobalActionsPanelSettingsActivity extends SettingsActivity {}
+    /**
+     * Activity for BugReportHandlerPicker.
+     */
+    public static class BugReportHandlerPickerActivity extends SettingsActivity { /* empty */ }
 
     // Top level categories for new IA
     public static class NetworkDashboardActivity extends SettingsActivity {}
diff --git a/src/com/android/settings/bugreporthandler/BugReportHandlerPicker.java b/src/com/android/settings/bugreporthandler/BugReportHandlerPicker.java
new file mode 100644
index 0000000..9c2ac9e
--- /dev/null
+++ b/src/com/android/settings/bugreporthandler/BugReportHandlerPicker.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2019 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.bugreporthandler;
+
+import static android.provider.Settings.ACTION_BUGREPORT_HANDLER_SETTINGS;
+
+import android.app.Activity;
+import android.app.settings.SettingsEnums;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
+import com.android.settingslib.applications.DefaultAppInfo;
+import com.android.settingslib.widget.FooterPreference;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Picker for BugReportHandler.
+ */
+public class BugReportHandlerPicker extends DefaultAppPickerFragment {
+    private static final String TAG = "BugReportHandlerPicker";
+
+    private BugReportHandlerUtil mBugReportHandlerUtil;
+    private FooterPreference mFooter;
+
+    private static String getHandlerApp(String key) {
+        int index = key.lastIndexOf('#');
+        String handlerApp = key.substring(0, index);
+        return handlerApp;
+    }
+
+    private static int getHandlerUser(String key) {
+        int index = key.lastIndexOf('#');
+        int handlerUser = 0;
+        try {
+            handlerUser = Integer.parseInt(key.substring(index + 1));
+        } catch (NumberFormatException nfe) {
+            Log.e(TAG, "Failed to get handlerUser");
+        }
+        return handlerUser;
+    }
+
+    @VisibleForTesting
+    static String getKey(String handlerApp, int handlerUser) {
+        return handlerApp + "#" + handlerUser;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.bug_report_handler_settings;
+    }
+
+    @Override
+    protected void addStaticPreferences(PreferenceScreen screen) {
+        if (mFooter == null) {
+            mFooter = new FooterPreference(screen.getContext());
+            mFooter.setIcon(R.drawable.ic_info_outline_24dp);
+            mFooter.setSingleLineTitle(false);
+            mFooter.setTitle(R.string.bug_report_handler_picker_footer_text);
+            mFooter.setSelectable(false);
+        }
+        screen.addPreference(mFooter);
+    }
+
+    @Override
+    protected List<DefaultAppInfo> getCandidates() {
+        final Context context = getContext();
+        final List<Pair<ApplicationInfo, Integer>> validBugReportHandlerInfos =
+                getBugReportHandlerUtil().getValidBugReportHandlerInfos(context);
+        final List<DefaultAppInfo> candidates = new ArrayList<>();
+        for (Pair<ApplicationInfo, Integer> info : validBugReportHandlerInfos) {
+            candidates.add(createDefaultAppInfo(context, mPm, info.second, info.first));
+        }
+        return candidates;
+    }
+
+    private BugReportHandlerUtil getBugReportHandlerUtil() {
+        if (mBugReportHandlerUtil == null) {
+            setBugReportHandlerUtil(createDefaultBugReportHandlerUtil());
+        }
+        return mBugReportHandlerUtil;
+    }
+
+    @VisibleForTesting
+    void setBugReportHandlerUtil(BugReportHandlerUtil bugReportHandlerUtil) {
+        mBugReportHandlerUtil = bugReportHandlerUtil;
+    }
+
+    @VisibleForTesting
+    BugReportHandlerUtil createDefaultBugReportHandlerUtil() {
+        return new BugReportHandlerUtil();
+    }
+
+    @Override
+    protected String getDefaultKey() {
+        final Pair<String, Integer> pair =
+                getBugReportHandlerUtil().getCurrentBugReportHandlerAppAndUser(getContext());
+        return getKey(pair.first, pair.second);
+    }
+
+    @Override
+    protected boolean setDefaultKey(String key) {
+        return getBugReportHandlerUtil().setCurrentBugReportHandlerAppAndUser(getContext(),
+                getHandlerApp(key),
+                getHandlerUser(key));
+    }
+
+    @Override
+    protected void onSelectionPerformed(boolean success) {
+        super.onSelectionPerformed(success);
+        if (success) {
+            final Activity activity = getActivity();
+            final Intent intent = activity == null ? null : activity.getIntent();
+            if (intent != null && ACTION_BUGREPORT_HANDLER_SETTINGS.equals(intent.getAction())) {
+                // If this was started through ACTION_BUGREPORT_HANDLER_SETTINGS then return once
+                // we have chosen a new handler.
+                getActivity().finish();
+            }
+        } else {
+            getBugReportHandlerUtil().showInvalidChoiceToast(getContext());
+            updateCandidates();
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return SettingsEnums.SETTINGS_BUGREPORT_HANDLER;
+    }
+
+    @VisibleForTesting
+    DefaultAppInfo createDefaultAppInfo(Context context, PackageManager pm, int userId,
+            PackageItemInfo packageItemInfo) {
+        return new BugreportHandlerAppInfo(context, pm, userId, packageItemInfo,
+                getDescription(packageItemInfo.packageName, userId));
+    }
+
+    private String getDescription(String handlerApp, int handlerUser) {
+        final Context context = getContext();
+        if (BugReportHandlerUtil.SHELL_APP_PACKAGE.equals(handlerApp)) {
+            return context.getString(R.string.system_default_app);
+        }
+        final UserHandle managedProfile = Utils.getManagedProfile(mUserManager);
+        if (managedProfile != null && managedProfile.getIdentifier() == handlerUser) {
+            return context.getString(R.string.work_profile_app);
+        }
+        return context.getString(R.string.personal_profile_app);
+    }
+
+    private static class BugreportHandlerAppInfo extends DefaultAppInfo {
+        private final Context mContext;
+
+        BugreportHandlerAppInfo(Context context, PackageManager pm, int userId,
+                PackageItemInfo packageItemInfo, String summary) {
+            super(context, pm, userId, packageItemInfo, summary, true /* enabled */);
+            mContext = context;
+        }
+
+        @Override
+        public String getKey() {
+            if (packageItemInfo != null) {
+                return BugReportHandlerPicker.getKey(packageItemInfo.packageName, userId);
+            } else {
+                return null;
+            }
+        }
+
+        @Override
+        public CharSequence loadLabel() {
+            if (mContext == null || packageItemInfo == null) {
+                return null;
+            }
+            if (BugReportHandlerUtil.SHELL_APP_PACKAGE.equals(packageItemInfo.packageName)) {
+                return mContext.getString(R.string.shell_app);
+            }
+            return super.loadLabel();
+        }
+    }
+}
diff --git a/src/com/android/settings/bugreporthandler/BugReportHandlerUtil.java b/src/com/android/settings/bugreporthandler/BugReportHandlerUtil.java
new file mode 100644
index 0000000..f4acc7d
--- /dev/null
+++ b/src/com/android/settings/bugreporthandler/BugReportHandlerUtil.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) 2019 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.bugreporthandler;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.UserInfo;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pair;
+import android.widget.Toast;
+
+import com.android.settings.R;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Utility methods related to BugReportHandler.
+ */
+public class BugReportHandlerUtil {
+    private static final String TAG = "BugReportHandlerUtil";
+    private static final String INTENT_BUGREPORT_REQUESTED =
+            "com.android.internal.intent.action.BUGREPORT_REQUESTED";
+
+    public static final String SHELL_APP_PACKAGE = "com.android.shell";
+
+    public BugReportHandlerUtil() {
+    }
+
+    /**
+     * Check is BugReportHandler enabled on the device.
+     *
+     * @param context Context
+     * @return true if BugReportHandler is enabled, or false otherwise
+     */
+    public boolean isBugReportHandlerEnabled(Context context) {
+        return context.getResources().getBoolean(
+                com.android.internal.R.bool.config_bugReportHandlerEnabled);
+    }
+
+    /**
+     * Fetch the package name currently used as bug report handler app and the user.
+     *
+     * @param context Context
+     * @return a pair of two values, first one is the current bug report handler app, second is
+     * the user.
+     */
+    public Pair<String, Integer> getCurrentBugReportHandlerAppAndUser(Context context) {
+
+        String handlerApp = getCustomBugReportHandlerApp(context);
+        int handlerUser = getCustomBugReportHandlerUser(context);
+
+        boolean needToResetOutdatedSettings = false;
+        if (!isBugreportWhitelistedApp(handlerApp)) {
+            handlerApp = getDefaultBugReportHandlerApp(context);
+            handlerUser = UserHandle.USER_SYSTEM;
+        } else if (getBugReportHandlerAppReceivers(context, handlerApp, handlerUser).isEmpty()) {
+            // It looks like the settings are outdated, need to reset outdated settings.
+            //
+            // i.e.
+            // If user chooses which profile and which bugreport-whitelisted app in that
+            // profile to handle a bugreport, then user remove the profile.
+            // === RESULT ===
+            // The chosen bugreport handler app is outdated because the profile is removed,
+            // so need to reset outdated settings
+            handlerApp = getDefaultBugReportHandlerApp(context);
+            handlerUser = UserHandle.USER_SYSTEM;
+            needToResetOutdatedSettings = true;
+        }
+
+        if (!isBugreportWhitelistedApp(handlerApp)
+                || getBugReportHandlerAppReceivers(context, handlerApp, handlerUser).isEmpty()) {
+            // It looks like current handler app may be too old and doesn't support to handle a
+            // bugreport, so change to let shell to handle a bugreport and need to reset
+            // settings.
+            handlerApp = SHELL_APP_PACKAGE;
+            handlerUser = UserHandle.USER_SYSTEM;
+            needToResetOutdatedSettings = true;
+        }
+
+        if (needToResetOutdatedSettings) {
+            setBugreportHandlerAppAndUser(context, handlerApp, handlerUser);
+        }
+
+        return Pair.create(handlerApp, handlerUser);
+    }
+
+    private String getCustomBugReportHandlerApp(Context context) {
+        // Get the package of custom bugreport handler app
+        return Settings.Global.getString(context.getContentResolver(),
+                Settings.Global.CUSTOM_BUGREPORT_HANDLER_APP);
+    }
+
+    private int getCustomBugReportHandlerUser(Context context) {
+        return Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.CUSTOM_BUGREPORT_HANDLER_USER, UserHandle.USER_NULL);
+    }
+
+    private String getDefaultBugReportHandlerApp(Context context) {
+        return context.getResources().getString(
+                com.android.internal.R.string.config_defaultBugReportHandlerApp);
+    }
+
+    /**
+     * Change current bug report handler app and user.
+     *
+     * @param context     Context
+     * @param handlerApp  the package name of the handler app
+     * @param handlerUser the id of the handler user
+     * @return whether the change succeeded
+     */
+    public boolean setCurrentBugReportHandlerAppAndUser(Context context, String handlerApp,
+            int handlerUser) {
+        if (!isBugreportWhitelistedApp(handlerApp)) {
+            return false;
+        } else if (getBugReportHandlerAppReceivers(context, handlerApp, handlerUser).isEmpty()) {
+            return false;
+        }
+        setBugreportHandlerAppAndUser(context, handlerApp, handlerUser);
+        return true;
+    }
+
+    /**
+     * Fetches ApplicationInfo objects and user ids for all currently valid BugReportHandler.
+     * A BugReportHandler is considered valid if it can receive BUGREPORT_REQUESTED intent.
+     *
+     * @param context Context
+     * @return pair objects for all currently valid BugReportHandler packages and user id
+     */
+    public List<Pair<ApplicationInfo, Integer>> getValidBugReportHandlerInfos(Context context) {
+        final List<Pair<ApplicationInfo, Integer>> validBugReportHandlerApplicationInfos =
+                new ArrayList<>();
+        List<String> bugreportWhitelistedPackages;
+        try {
+            bugreportWhitelistedPackages =
+                    ActivityManager.getService().getBugreportWhitelistedPackages();
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get bugreportWhitelistedPackages:", e);
+            return validBugReportHandlerApplicationInfos;
+        }
+
+        // Add "Shell with system user" as System default preference on top of screen
+        if (bugreportWhitelistedPackages.contains(SHELL_APP_PACKAGE)
+                && !getBugReportHandlerAppReceivers(context, SHELL_APP_PACKAGE,
+                UserHandle.USER_SYSTEM).isEmpty()) {
+            try {
+                validBugReportHandlerApplicationInfos.add(
+                        Pair.create(
+                                context.getPackageManager().getApplicationInfo(SHELL_APP_PACKAGE,
+                                        PackageManager.MATCH_ANY_USER), UserHandle.USER_SYSTEM)
+                );
+            } catch (PackageManager.NameNotFoundException e) {
+            }
+        }
+
+        final UserManager userManager = context.getSystemService(UserManager.class);
+        final List<UserInfo> profileList = userManager.getProfiles(UserHandle.getCallingUserId());
+        // Only add non-Shell app as normal preference
+        final List<String> nonShellPackageList = bugreportWhitelistedPackages.stream()
+                .filter(pkg -> !SHELL_APP_PACKAGE.equals(pkg)).collect(Collectors.toList());
+        Collections.sort(nonShellPackageList);
+        for (String pkg : nonShellPackageList) {
+            for (UserInfo profile : profileList) {
+                final int userId = profile.getUserHandle().getIdentifier();
+                if (getBugReportHandlerAppReceivers(context, pkg, userId).isEmpty()) {
+                    continue;
+                }
+                try {
+                    validBugReportHandlerApplicationInfos.add(
+                            Pair.create(context.getPackageManager()
+                                            .getApplicationInfo(pkg, PackageManager.MATCH_ANY_USER),
+                                    userId));
+                } catch (PackageManager.NameNotFoundException e) {
+                }
+            }
+        }
+        return validBugReportHandlerApplicationInfos;
+    }
+
+    private boolean isBugreportWhitelistedApp(String app) {
+        // Verify the app is bugreport-whitelisted
+        if (TextUtils.isEmpty(app)) {
+            return false;
+        }
+        try {
+            return ActivityManager.getService().getBugreportWhitelistedPackages().contains(app);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to get bugreportWhitelistedPackages:", e);
+            return false;
+        }
+    }
+
+    private List<ResolveInfo> getBugReportHandlerAppReceivers(Context context, String handlerApp,
+            int handlerUser) {
+        // Use the app package and the user id to retrieve the receiver that can handle a
+        // broadcast of the intent.
+        final Intent intent = new Intent(INTENT_BUGREPORT_REQUESTED);
+        intent.setPackage(handlerApp);
+        return context.getPackageManager()
+                .queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_SYSTEM_ONLY,
+                        handlerUser);
+    }
+
+    private void setBugreportHandlerAppAndUser(Context context, String handlerApp,
+            int handlerUser) {
+        Settings.Global.putString(context.getContentResolver(),
+                Settings.Global.CUSTOM_BUGREPORT_HANDLER_APP,
+                handlerApp);
+        Settings.Global.putInt(context.getContentResolver(),
+                Settings.Global.CUSTOM_BUGREPORT_HANDLER_USER, handlerUser);
+    }
+
+    /**
+     * Show a toast to explain the chosen bug report handler can no longer be chosen.
+     */
+    public void showInvalidChoiceToast(Context context) {
+        final Toast toast = Toast.makeText(context,
+                R.string.select_invalid_bug_report_handler_toast_text, Toast.LENGTH_SHORT);
+        toast.show();
+    }
+}
diff --git a/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 4ad4c5f..01b1598 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -56,6 +56,7 @@
 import com.android.settings.biometrics.face.FaceSettings;
 import com.android.settings.biometrics.fingerprint.FingerprintSettings;
 import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
+import com.android.settings.bugreporthandler.BugReportHandlerPicker;
 import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
 import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
 import com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment;
@@ -106,14 +107,14 @@
 import com.android.settings.network.NetworkDashboardFragment;
 import com.android.settings.nfc.AndroidBeam;
 import com.android.settings.nfc.PaymentSettings;
-import com.android.settings.notification.app.AppBubbleNotificationSettings;
-import com.android.settings.notification.app.AppNotificationSettings;
-import com.android.settings.notification.app.ChannelNotificationSettings;
 import com.android.settings.notification.ConfigureNotificationSettings;
 import com.android.settings.notification.NotificationAccessSettings;
 import com.android.settings.notification.NotificationAssistantPicker;
-import com.android.settings.notification.history.NotificationStation;
 import com.android.settings.notification.SoundSettings;
+import com.android.settings.notification.app.AppBubbleNotificationSettings;
+import com.android.settings.notification.app.AppNotificationSettings;
+import com.android.settings.notification.app.ChannelNotificationSettings;
+import com.android.settings.notification.history.NotificationStation;
 import com.android.settings.notification.zen.ZenAccessSettings;
 import com.android.settings.notification.zen.ZenModeAutomationSettings;
 import com.android.settings.notification.zen.ZenModeBlockedEffectsSettings;
@@ -287,7 +288,8 @@
             BatterySaverScheduleSettings.class.getName(),
             MobileNetworkListFragment.class.getName(),
             GlobalActionsPanelSettings.class.getName(),
-            DarkModeSettingsFragment.class.getName()
+            DarkModeSettingsFragment.class.getName(),
+            BugReportHandlerPicker.class.getName()
     };
 
     public static final String[] SETTINGS_FOR_RESTRICTED = {
diff --git a/src/com/android/settings/development/BugReportHandlerPreferenceController.java b/src/com/android/settings/development/BugReportHandlerPreferenceController.java
new file mode 100644
index 0000000..b95d31b
--- /dev/null
+++ b/src/com/android/settings/development/BugReportHandlerPreferenceController.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2019 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.development;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.os.UserManager;
+import android.text.TextUtils;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+
+import com.android.settings.R;
+import com.android.settings.bugreporthandler.BugReportHandlerUtil;
+import com.android.settings.core.PreferenceControllerMixin;
+import com.android.settingslib.development.DeveloperOptionsPreferenceController;
+
+/**
+ * PreferenceController for BugReportHandler
+ */
+public class BugReportHandlerPreferenceController extends DeveloperOptionsPreferenceController
+        implements PreferenceControllerMixin {
+
+    private static final String KEY_BUG_REPORT_HANDLER = "bug_report_handler";
+
+    private final UserManager mUserManager;
+    private final BugReportHandlerUtil mBugReportHandlerUtil;
+
+    public BugReportHandlerPreferenceController(Context context) {
+        super(context);
+        mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
+        mBugReportHandlerUtil = new BugReportHandlerUtil();
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return !mUserManager.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES)
+                && mBugReportHandlerUtil.isBugReportHandlerEnabled(mContext);
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_BUG_REPORT_HANDLER;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        final CharSequence currentBugReportHandlerAppLabel = getCurrentBugReportHandlerAppLabel();
+        if (!TextUtils.isEmpty(currentBugReportHandlerAppLabel)) {
+            mPreference.setSummary(currentBugReportHandlerAppLabel);
+        } else {
+            mPreference.setSummary(R.string.app_list_preference_none);
+        }
+    }
+
+    @VisibleForTesting
+    CharSequence getCurrentBugReportHandlerAppLabel() {
+        final String handlerApp = mBugReportHandlerUtil.getCurrentBugReportHandlerAppAndUser(
+                mContext).first;
+        if (BugReportHandlerUtil.SHELL_APP_PACKAGE.equals(handlerApp)) {
+            return mContext.getString(R.string.shell_app);
+        }
+        ApplicationInfo applicationInfo;
+        try {
+            applicationInfo = mContext.getPackageManager().getApplicationInfo(handlerApp,
+                    PackageManager.MATCH_ANY_USER);
+        } catch (PackageManager.NameNotFoundException e) {
+            return null;
+        }
+        return applicationInfo.loadLabel(mContext.getPackageManager());
+    }
+}
diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
index 7fc898b..b3bbf75 100644
--- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
+++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java
@@ -419,6 +419,7 @@
         final List<AbstractPreferenceController> controllers = new ArrayList<>();
         controllers.add(new MemoryUsagePreferenceController(context));
         controllers.add(new BugReportPreferenceController(context));
+        controllers.add(new BugReportHandlerPreferenceController(context));
         controllers.add(new SystemServerHeapDumpPreferenceController(context));
         controllers.add(new LocalBackupPasswordPreferenceController(context));
         controllers.add(new StayAwakePreferenceController(context, lifecycle));