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
This commit is contained in:
@@ -1974,6 +1974,18 @@
|
|||||||
<activity android:name="Settings$WebViewAppPickerActivity"
|
<activity android:name="Settings$WebViewAppPickerActivity"
|
||||||
android:label="@string/select_webview_provider_dialog_title" />
|
android:label="@string/select_webview_provider_dialog_title" />
|
||||||
|
|
||||||
|
<activity android:name="Settings$BugReportHandlerPickerActivity"
|
||||||
|
android:label="@string/bug_report_handler_title"
|
||||||
|
android:exported="true"
|
||||||
|
android:excludeFromRecents="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.settings.BUGREPORT_HANDLER_SETTINGS" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data android:name="com.android.settings.FRAGMENT_CLASS"
|
||||||
|
android:value="com.android.settings.bugreporthandler.BugReportHandlerPicker" />
|
||||||
|
</activity>
|
||||||
|
|
||||||
<activity android:name=".bluetooth.BluetoothPairingDialog"
|
<activity android:name=".bluetooth.BluetoothPairingDialog"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:windowSoftInputMode="stateVisible|adjustResize"
|
android:windowSoftInputMode="stateVisible|adjustResize"
|
||||||
|
@@ -11361,4 +11361,22 @@
|
|||||||
<!-- DSU Loader Loading. Do not translate. -->
|
<!-- DSU Loader Loading. Do not translate. -->
|
||||||
<string name="dsu_loader_loading" translatable="false">Loading...</string>
|
<string name="dsu_loader_loading" translatable="false">Loading...</string>
|
||||||
|
|
||||||
|
<!-- Name of dev option called "Bug report handler" [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="bug_report_handler_title">Bug report handler</string>
|
||||||
|
|
||||||
|
<!-- Developer Settings: Footer text for bug report handler picker [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="bug_report_handler_picker_footer_text">Determines which app handles the Bug Report shortcut on your device.</string>
|
||||||
|
|
||||||
|
<!-- Label of personal profile app for current setting [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="personal_profile_app">(Personal)</string>
|
||||||
|
|
||||||
|
<!-- Label of work profile app for current setting [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="work_profile_app">(Work)</string>
|
||||||
|
|
||||||
|
<!-- Title of Shell app for current setting [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="shell_app">Android System (Shell)</string>
|
||||||
|
|
||||||
|
<!-- Developer settings: text for the bug report handler selection toast shown if an invalid bug report handler was chosen. [CHAR LIMIT=NONE] -->
|
||||||
|
<string name="select_invalid_bug_report_handler_toast_text">This choice is no longer valid. Try again.</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
23
res/xml/bug_report_handler_settings.xml
Normal file
23
res/xml/bug_report_handler_settings.xml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:settings="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:title="@string/bug_report_handler_title"
|
||||||
|
settings:staticPreferenceLocation="append" >
|
||||||
|
</PreferenceScreen>
|
@@ -35,6 +35,11 @@
|
|||||||
android:title="@*android:string/bugreport_title"
|
android:title="@*android:string/bugreport_title"
|
||||||
android:dialogTitle="@*android:string/bugreport_title" />
|
android:dialogTitle="@*android:string/bugreport_title" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:key="bug_report_handler"
|
||||||
|
android:title="@string/bug_report_handler_title"
|
||||||
|
android:fragment="com.android.settings.bugreporthandler.BugReportHandlerPicker" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="system_server_heap_dump"
|
android:key="system_server_heap_dump"
|
||||||
android:title="@string/capture_system_heap_dump_title" />
|
android:title="@string/capture_system_heap_dump_title" />
|
||||||
|
@@ -169,6 +169,10 @@ public class Settings extends SettingsActivity {
|
|||||||
public static class WifiCallingDisclaimerActivity extends SettingsActivity { /* empty */ }
|
public static class WifiCallingDisclaimerActivity extends SettingsActivity { /* empty */ }
|
||||||
public static class MobileNetworkListActivity extends SettingsActivity {}
|
public static class MobileNetworkListActivity extends SettingsActivity {}
|
||||||
public static class GlobalActionsPanelSettingsActivity extends SettingsActivity {}
|
public static class GlobalActionsPanelSettingsActivity extends SettingsActivity {}
|
||||||
|
/**
|
||||||
|
* Activity for BugReportHandlerPicker.
|
||||||
|
*/
|
||||||
|
public static class BugReportHandlerPickerActivity extends SettingsActivity { /* empty */ }
|
||||||
|
|
||||||
// Top level categories for new IA
|
// Top level categories for new IA
|
||||||
public static class NetworkDashboardActivity extends SettingsActivity {}
|
public static class NetworkDashboardActivity extends SettingsActivity {}
|
||||||
|
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
@@ -56,6 +56,7 @@ import com.android.settings.backup.UserBackupSettingsActivity;
|
|||||||
import com.android.settings.biometrics.face.FaceSettings;
|
import com.android.settings.biometrics.face.FaceSettings;
|
||||||
import com.android.settings.biometrics.fingerprint.FingerprintSettings;
|
import com.android.settings.biometrics.fingerprint.FingerprintSettings;
|
||||||
import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
|
import com.android.settings.bluetooth.BluetoothDeviceDetailsFragment;
|
||||||
|
import com.android.settings.bugreporthandler.BugReportHandlerPicker;
|
||||||
import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
|
import com.android.settings.connecteddevice.AdvancedConnectedDeviceDashboardFragment;
|
||||||
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
|
import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment;
|
||||||
import com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment;
|
import com.android.settings.connecteddevice.PreviouslyConnectedDeviceDashboardFragment;
|
||||||
@@ -106,14 +107,14 @@ import com.android.settings.network.MobileNetworkListFragment;
|
|||||||
import com.android.settings.network.NetworkDashboardFragment;
|
import com.android.settings.network.NetworkDashboardFragment;
|
||||||
import com.android.settings.nfc.AndroidBeam;
|
import com.android.settings.nfc.AndroidBeam;
|
||||||
import com.android.settings.nfc.PaymentSettings;
|
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.ConfigureNotificationSettings;
|
||||||
import com.android.settings.notification.NotificationAccessSettings;
|
import com.android.settings.notification.NotificationAccessSettings;
|
||||||
import com.android.settings.notification.NotificationAssistantPicker;
|
import com.android.settings.notification.NotificationAssistantPicker;
|
||||||
import com.android.settings.notification.history.NotificationStation;
|
|
||||||
import com.android.settings.notification.SoundSettings;
|
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.ZenAccessSettings;
|
||||||
import com.android.settings.notification.zen.ZenModeAutomationSettings;
|
import com.android.settings.notification.zen.ZenModeAutomationSettings;
|
||||||
import com.android.settings.notification.zen.ZenModeBlockedEffectsSettings;
|
import com.android.settings.notification.zen.ZenModeBlockedEffectsSettings;
|
||||||
@@ -287,7 +288,8 @@ public class SettingsGateway {
|
|||||||
BatterySaverScheduleSettings.class.getName(),
|
BatterySaverScheduleSettings.class.getName(),
|
||||||
MobileNetworkListFragment.class.getName(),
|
MobileNetworkListFragment.class.getName(),
|
||||||
GlobalActionsPanelSettings.class.getName(),
|
GlobalActionsPanelSettings.class.getName(),
|
||||||
DarkModeSettingsFragment.class.getName()
|
DarkModeSettingsFragment.class.getName(),
|
||||||
|
BugReportHandlerPicker.class.getName()
|
||||||
};
|
};
|
||||||
|
|
||||||
public static final String[] SETTINGS_FOR_RESTRICTED = {
|
public static final String[] SETTINGS_FOR_RESTRICTED = {
|
||||||
|
@@ -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());
|
||||||
|
}
|
||||||
|
}
|
@@ -419,6 +419,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
|
|||||||
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
final List<AbstractPreferenceController> controllers = new ArrayList<>();
|
||||||
controllers.add(new MemoryUsagePreferenceController(context));
|
controllers.add(new MemoryUsagePreferenceController(context));
|
||||||
controllers.add(new BugReportPreferenceController(context));
|
controllers.add(new BugReportPreferenceController(context));
|
||||||
|
controllers.add(new BugReportHandlerPreferenceController(context));
|
||||||
controllers.add(new SystemServerHeapDumpPreferenceController(context));
|
controllers.add(new SystemServerHeapDumpPreferenceController(context));
|
||||||
controllers.add(new LocalBackupPasswordPreferenceController(context));
|
controllers.add(new LocalBackupPasswordPreferenceController(context));
|
||||||
controllers.add(new StayAwakePreferenceController(context, lifecycle));
|
controllers.add(new StayAwakePreferenceController(context, lifecycle));
|
||||||
|
@@ -0,0 +1,177 @@
|
|||||||
|
/*
|
||||||
|
* 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 static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.doNothing;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.content.pm.PackageInfo;
|
||||||
|
import android.graphics.drawable.ColorDrawable;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import androidx.fragment.app.FragmentActivity;
|
||||||
|
|
||||||
|
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||||
|
import com.android.settingslib.widget.RadioButtonPreference;
|
||||||
|
|
||||||
|
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.RobolectricTestRunner;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.Shadows;
|
||||||
|
import org.robolectric.shadows.ShadowPackageManager;
|
||||||
|
import org.robolectric.util.ReflectionHelpers;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class BugReportHandlerPickerTest {
|
||||||
|
private static final String PACKAGE_NAME = "com.example.test";
|
||||||
|
private static final int USER_ID = 0;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private FragmentActivity mActivity;
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private ShadowPackageManager mPackageManager;
|
||||||
|
private BugReportHandlerPicker mPicker;
|
||||||
|
private BugReportHandlerUtil mBugReportHandlerUtil;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mContext = spy(RuntimeEnvironment.application);
|
||||||
|
mPackageManager = Shadows.shadowOf(mContext.getPackageManager());
|
||||||
|
|
||||||
|
final ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||||
|
applicationInfo.name = PACKAGE_NAME;
|
||||||
|
applicationInfo.uid = 0;
|
||||||
|
applicationInfo.flags = 0;
|
||||||
|
applicationInfo.packageName = PACKAGE_NAME;
|
||||||
|
|
||||||
|
final PackageInfo packageInfo = new PackageInfo();
|
||||||
|
packageInfo.packageName = PACKAGE_NAME;
|
||||||
|
packageInfo.applicationInfo = applicationInfo;
|
||||||
|
mPackageManager.addPackage(packageInfo);
|
||||||
|
mPackageManager.setUnbadgedApplicationIcon(PACKAGE_NAME, new ColorDrawable());
|
||||||
|
|
||||||
|
mPicker = spy(new BugReportHandlerPicker());
|
||||||
|
doNothing().when(mPicker).updateCandidates();
|
||||||
|
doNothing().when(mPicker).updateCheckedState(any());
|
||||||
|
doReturn(mActivity).when(mPicker).getActivity();
|
||||||
|
|
||||||
|
ReflectionHelpers.setField(mPicker, "mMetricsFeatureProvider",
|
||||||
|
mock(MetricsFeatureProvider.class));
|
||||||
|
mBugReportHandlerUtil = mock(BugReportHandlerUtil.class);
|
||||||
|
mPicker.setBugReportHandlerUtil(mBugReportHandlerUtil);
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void tearDown() {
|
||||||
|
mPackageManager.removePackage(PACKAGE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clickItem_success() {
|
||||||
|
testClickingItemSuccess();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clickItem_fail() {
|
||||||
|
testClickingItemFail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clickItem_usingBugReportHandlerSettingIntent_success() {
|
||||||
|
useBugReportHandlerSettingIntent();
|
||||||
|
testClickingItemSuccess();
|
||||||
|
verify(mActivity, times(1)).finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void clickItem_fromBugReportHandlerSettingIntent_fail() {
|
||||||
|
useBugReportHandlerSettingIntent();
|
||||||
|
testClickingItemFail();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ApplicationInfo createApplicationInfo(String packageName) {
|
||||||
|
ApplicationInfo applicationInfo = new ApplicationInfo();
|
||||||
|
applicationInfo.packageName = packageName;
|
||||||
|
return applicationInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testClickingItemSuccess() {
|
||||||
|
when(mBugReportHandlerUtil.getValidBugReportHandlerInfos(any()))
|
||||||
|
.thenReturn(Collections.singletonList(Pair.create(
|
||||||
|
createApplicationInfo(PACKAGE_NAME), USER_ID)));
|
||||||
|
when(mBugReportHandlerUtil.setCurrentBugReportHandlerAppAndUser(any(), eq(PACKAGE_NAME),
|
||||||
|
eq(USER_ID))).thenReturn(true);
|
||||||
|
|
||||||
|
RadioButtonPreference defaultPackagePref = mock(RadioButtonPreference.class);
|
||||||
|
when(defaultPackagePref.getKey()).thenReturn(
|
||||||
|
BugReportHandlerPicker.getKey(PACKAGE_NAME, USER_ID));
|
||||||
|
mPicker.onRadioButtonClicked(defaultPackagePref);
|
||||||
|
|
||||||
|
verify(mBugReportHandlerUtil, times(1)).setCurrentBugReportHandlerAppAndUser(any(),
|
||||||
|
eq(PACKAGE_NAME), eq(USER_ID));
|
||||||
|
verify(mPicker, times(1)).updateCheckedState(
|
||||||
|
BugReportHandlerPicker.getKey(PACKAGE_NAME, USER_ID));
|
||||||
|
verify(mBugReportHandlerUtil, never()).showInvalidChoiceToast(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testClickingItemFail() {
|
||||||
|
when(mBugReportHandlerUtil.getValidBugReportHandlerInfos(any()))
|
||||||
|
.thenReturn(Collections.singletonList(Pair.create(
|
||||||
|
createApplicationInfo(PACKAGE_NAME), USER_ID)));
|
||||||
|
when(mBugReportHandlerUtil.setCurrentBugReportHandlerAppAndUser(any(), eq(PACKAGE_NAME),
|
||||||
|
eq(USER_ID))).thenReturn(false);
|
||||||
|
|
||||||
|
RadioButtonPreference defaultPackagePref = mock(RadioButtonPreference.class);
|
||||||
|
when(defaultPackagePref.getKey()).thenReturn(
|
||||||
|
BugReportHandlerPicker.getKey(PACKAGE_NAME, USER_ID));
|
||||||
|
mPicker.onRadioButtonClicked(defaultPackagePref);
|
||||||
|
|
||||||
|
verify(mBugReportHandlerUtil, times(1)).setCurrentBugReportHandlerAppAndUser(any(),
|
||||||
|
eq(PACKAGE_NAME), eq(USER_ID));
|
||||||
|
// Ensure we update the list of packages when we click a non-valid package - the list must
|
||||||
|
// have changed, otherwise this click wouldn't fail.
|
||||||
|
verify(mPicker, times(1)).updateCandidates();
|
||||||
|
verify(mBugReportHandlerUtil, times(1)).showInvalidChoiceToast(any());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void useBugReportHandlerSettingIntent() {
|
||||||
|
Intent intent = new Intent(ACTION_BUGREPORT_HANDLER_SETTINGS);
|
||||||
|
when(mActivity.getIntent()).thenReturn(intent);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* 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 static com.google.common.truth.Truth.assertThat;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
|
import static org.mockito.Mockito.spy;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.UserManager;
|
||||||
|
|
||||||
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.bugreporthandler.BugReportHandlerUtil;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
import org.robolectric.RobolectricTestRunner;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
|
import org.robolectric.util.ReflectionHelpers;
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner.class)
|
||||||
|
public class BugReportHandlerPreferenceControllerTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PreferenceScreen mPreferenceScreen;
|
||||||
|
@Mock
|
||||||
|
private UserManager mUserManager;
|
||||||
|
@Mock
|
||||||
|
private BugReportHandlerUtil mBugReportHandlerUtil;
|
||||||
|
@Mock
|
||||||
|
private Preference mPreference;
|
||||||
|
|
||||||
|
private BugReportHandlerPreferenceController mController;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
mController = spy(new BugReportHandlerPreferenceController(RuntimeEnvironment.application));
|
||||||
|
ReflectionHelpers.setField(mController, "mUserManager", mUserManager);
|
||||||
|
ReflectionHelpers.setField(mController, "mBugReportHandlerUtil", mBugReportHandlerUtil);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable_hasDebugRestriction_notAvailable() {
|
||||||
|
doReturn(true).when(mUserManager).hasUserRestriction(anyString());
|
||||||
|
doReturn(true).when(mBugReportHandlerUtil).isBugReportHandlerEnabled(any(Context.class));
|
||||||
|
|
||||||
|
assertThat(mController.isAvailable()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable_bugReportHandlerDisabled_notAvailable() {
|
||||||
|
doReturn(false).when(mBugReportHandlerUtil).isBugReportHandlerEnabled(any(Context.class));
|
||||||
|
doReturn(false).when(mUserManager).hasUserRestriction(anyString());
|
||||||
|
|
||||||
|
assertThat(mController.isAvailable()).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isAvailable_noDebugRestrictionAndBugReportHandlerEnabled_available() {
|
||||||
|
doReturn(false).when(mUserManager).hasUserRestriction(anyString());
|
||||||
|
doReturn(true).when(mBugReportHandlerUtil).isBugReportHandlerEnabled(any(Context.class));
|
||||||
|
|
||||||
|
assertThat(mController.isAvailable()).isTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateState_hasCurrentBugReportHandlerAppLabel_setAppLabel() {
|
||||||
|
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
|
||||||
|
.thenReturn(mPreference);
|
||||||
|
mController.displayPreference(mPreferenceScreen);
|
||||||
|
doReturn("SomeRandomAppLabel!!!").when(mController).getCurrentBugReportHandlerAppLabel();
|
||||||
|
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
verify(mPreference).setSummary("SomeRandomAppLabel!!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void updateState_noCurrentBugReportHandlerAppLabel_setAppDefaultLabel() {
|
||||||
|
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
|
||||||
|
.thenReturn(mPreference);
|
||||||
|
mController.displayPreference(mPreferenceScreen);
|
||||||
|
doReturn(null).when(mController).getCurrentBugReportHandlerAppLabel();
|
||||||
|
|
||||||
|
mController.updateState(mPreference);
|
||||||
|
|
||||||
|
verify(mPreference).setSummary(R.string.app_list_preference_none);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user