GUP: Display a list of Apps and dialogs

1) Add preference controller for gup dashboard and add list preferences
for each entry of the apps
2) Add gup dashboard page to search index
3) Add comprehensive tests for GupPreferenceController

Bug: 119221883
Test: make RunSettingsRoboTests
Change-Id: Ide4934c0dd3901532723e77e74663e5a7b639026
This commit is contained in:
Yiwei Zhang
2018-12-29 08:52:31 +08:00
parent c81a03b60e
commit 83c030f1cd
11 changed files with 490 additions and 272 deletions

View File

@@ -10042,17 +10042,24 @@
<!-- UI debug setting: ANGLE enabled app has been set [CHAR LIMIT=NONE] --> <!-- UI debug setting: ANGLE enabled app has been set [CHAR LIMIT=NONE] -->
<string name="angle_enabled_app_set">ANGLE enabled application: <xliff:g id="app_name" example="com.company.app">%1$s</xliff:g></string> <string name="angle_enabled_app_set">ANGLE enabled application: <xliff:g id="app_name" example="com.company.app">%1$s</xliff:g></string>
<!-- UI debug setting: select an app to use Game Update Package [CHAR LIMIT=100] -->
<string name="gup_dev_opt_in_app">Use Game Update Package</string>
<!-- UI debug setting: no app selected to use Game Update Package [CHAR LIMIT=100] -->
<string name="gup_dev_opt_in_app_not_set">No selected app</string>
<!-- UI debug setting: app selected to use Game Update Package [CHAR LIMIT=NONE] -->
<string name="gup_dev_opt_in_app_set"><xliff:g id="app_name" example="com.company.app">%1$s</xliff:g></string>
<!-- Title for Game Update Packages dashboard where developers can configure apps to use GUP or not [CHAR LIMIT=50] --> <!-- Title for Game Update Packages dashboard where developers can configure apps to use GUP or not [CHAR LIMIT=50] -->
<string name="gup_dashboard_title">Game Update Packages Preferences</string> <string name="gup_dashboard_title">Game Update Packages Preferences</string>
<!-- Summary for Game Update Packages dashboard [CHAR LIMIT=50] --> <!-- Summary for Game Update Packages dashboard [CHAR LIMIT=50] -->
<string name="gup_dashboard_summary">Modify Game Update Packages settings</string> <string name="gup_dashboard_summary">Modify Game Update Packages settings</string>
<!-- Title for Game Update Packages preference [CHAR LIMIT=50] -->
<string name="gup_app_preference_title">Select Graphics Driver</string>
<!-- The default value for Game Update Packages preference [CHAR LIMIT=50] -->
<string name="gup_app_preference_default">Default</string>
<!-- The gup value for Game Update Packages preference [CHAR LIMIT=50] -->
<string name="gup_app_preference_gup">Game Update Packages</string>
<!-- The native value for Game Update Packages preference [CHAR LIMIT=50] -->
<string name="gup_app_preference_native">Native Graphics Driver</string>
<!-- All the values for Game Update Packages preference [CHAR LIMIT=50] -->
<string-array name="gup_app_preference_values">
<item>@string/gup_app_preference_default</item>
<item>@string/gup_app_preference_gup</item>
<item>@string/gup_app_preference_native</item>
</string-array>
<!-- Slices Strings --> <!-- Slices Strings -->

View File

@@ -195,7 +195,8 @@
android:key="gup_dashboard" android:key="gup_dashboard"
android:title="@string/gup_dashboard_title" android:title="@string/gup_dashboard_title"
android:summary="@string/gup_dashboard_summary" android:summary="@string/gup_dashboard_summary"
android:fragment="com.android.settings.development.gup.GupDashboard" /> android:fragment="com.android.settings.development.gup.GupDashboard"
settings:searchable="false" />
</PreferenceCategory> </PreferenceCategory>
@@ -430,11 +431,6 @@
android:summary="%s" android:summary="%s"
android:title="@string/simulate_color_space" /> android:title="@string/simulate_color_space" />
<Preference
android:title="@string/gup_dev_opt_in_app"
android:key="gup_dev_opt_in_app"
android:summary="@string/gup_dev_opt_in_app_summary" />
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory

View File

@@ -17,4 +17,14 @@
<PreferenceScreen <PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/gup_dashboard_title" /> xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="gup_settings"
android:title="@string/gup_dashboard_title">
<PreferenceCategory
android:key="gup_category"
android:title="@string/gup_app_preference_title"
settings:controller="com.android.settings.development.gup.GupPreferenceController">
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -31,6 +31,4 @@ public interface DevelopmentOptionsActivityRequestCodes {
int REQUEST_CODE_ANGLE_DRIVER_PKGS = 4; int REQUEST_CODE_ANGLE_DRIVER_PKGS = 4;
int REQUEST_CODE_ANGLE_DRIVER_VALUES = 5; int REQUEST_CODE_ANGLE_DRIVER_VALUES = 5;
int REQUEST_CODE_GUP_DEV_OPT_IN_APPS = 6;
} }

View File

@@ -423,7 +423,6 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra
controllers.add(new SelectDebugAppPreferenceController(context, fragment)); controllers.add(new SelectDebugAppPreferenceController(context, fragment));
controllers.add(new WaitForDebuggerPreferenceController(context)); controllers.add(new WaitForDebuggerPreferenceController(context));
controllers.add(new EnableGpuDebugLayersPreferenceController(context)); controllers.add(new EnableGpuDebugLayersPreferenceController(context));
controllers.add(new GameUpdatePackageDevOptInPreferenceController(context, fragment));
controllers.add(new VerifyAppsOverUsbPreferenceController(context)); controllers.add(new VerifyAppsOverUsbPreferenceController(context));
controllers.add(new LogdSizePreferenceController(context)); controllers.add(new LogdSizePreferenceController(context));
controllers.add(new LogPersistPreferenceController(context, fragment, lifecycle)); controllers.add(new LogPersistPreferenceController(context, fragment, lifecycle));

View File

@@ -1,121 +0,0 @@
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development;
import static com.android.settings.development.DevelopmentOptionsActivityRequestCodes
.REQUEST_CODE_GUP_DEV_OPT_IN_APPS;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.development.DeveloperOptionsPreferenceController;
// TODO(b/119221883): Need to override isAvailable() to return false when updatable graphics driver is not supported.
public class GameUpdatePackageDevOptInPreferenceController
extends DeveloperOptionsPreferenceController
implements PreferenceControllerMixin, OnActivityResultListener {
private static final String GUP_DEV_OPT_IN_APP_KEY = "gup_dev_opt_in_app";
private final DevelopmentSettingsDashboardFragment mFragment;
private final PackageManager mPackageManager;
public GameUpdatePackageDevOptInPreferenceController(Context context,
DevelopmentSettingsDashboardFragment fragment) {
super(context);
mFragment = fragment;
mPackageManager = mContext.getPackageManager();
}
@Override
public String getPreferenceKey() {
return GUP_DEV_OPT_IN_APP_KEY;
}
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
if (GUP_DEV_OPT_IN_APP_KEY.equals(preference.getKey())) {
// pass it on to settings
final Intent intent = getActivityStartIntent();
mFragment.startActivityForResult(intent, REQUEST_CODE_GUP_DEV_OPT_IN_APPS);
return true;
}
return false;
}
@Override
public void updateState(Preference preference) {
updatePreferenceSummary();
}
@Override
public boolean onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != REQUEST_CODE_GUP_DEV_OPT_IN_APPS
|| resultCode != Activity.RESULT_OK) {
return false;
}
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.GUP_DEV_OPT_IN_APPS, data.getAction());
updatePreferenceSummary();
return true;
}
@Override
protected void onDeveloperOptionsSwitchDisabled() {
super.onDeveloperOptionsSwitchDisabled();
mPreference.setSummary(mContext.getResources().getString(
R.string.gup_dev_opt_in_app_not_set));
}
@VisibleForTesting
Intent getActivityStartIntent() {
Intent intent = new Intent(mContext, AppPicker.class);
intent.putExtra(AppPicker.EXTRA_NON_SYSTEM, true /* value */);
return intent;
}
private void updatePreferenceSummary() {
final String optInApp = Settings.Global.getString(
mContext.getContentResolver(), Settings.Global.GUP_DEV_OPT_IN_APPS);
if (optInApp != null && !optInApp.isEmpty()) {
mPreference.setSummary(mContext.getResources().getString(
R.string.gup_dev_opt_in_app_set, getAppLabel(optInApp)));
} else {
mPreference.setSummary(mContext.getResources().getString(
R.string.gup_dev_opt_in_app_not_set));
}
}
private String getAppLabel(String applicationPackageName) {
try {
final ApplicationInfo ai = mPackageManager.getApplicationInfo(applicationPackageName,
PackageManager.GET_DISABLED_COMPONENTS);
final CharSequence lab = mPackageManager.getApplicationLabel(ai);
return lab != null ? lab.toString() : applicationPackageName;
} catch (PackageManager.NameNotFoundException e) {
return applicationPackageName;
}
}
}

View File

@@ -17,14 +17,22 @@
package com.android.settings.development.gup; package com.android.settings.development.gup;
import android.content.Context; import android.content.Context;
import android.provider.SearchIndexableResource;
import com.android.internal.logging.nano.MetricsProto; import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment; import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settings.search.Indexable;
import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.development.DevelopmentSettingsEnabler;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.List; import java.util.List;
@SearchIndexable
public class GupDashboard extends DashboardFragment { public class GupDashboard extends DashboardFragment {
private static final String TAG = "GupDashboard"; private static final String TAG = "GupDashboard";
@@ -47,4 +55,22 @@ public class GupDashboard extends DashboardFragment {
public int getHelpResource() { public int getHelpResource() {
return 0; return 0;
} }
public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
new BaseSearchIndexProvider() {
@Override
public List<SearchIndexableResource> getXmlResourcesToIndex(
Context context, boolean enabled) {
final List<SearchIndexableResource> result = new ArrayList<>();
final SearchIndexableResource sir = new SearchIndexableResource(context);
sir.xmlResId = R.xml.gup_settings;
result.add(sir);
return result;
}
@Override
protected boolean isPageSearchEnabled(Context context) {
return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context);
}
};
} }

View File

@@ -0,0 +1,206 @@
/*
* Copyright 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.gup;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.development.DevelopmentSettingsEnabler;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class GupPreferenceController
extends BasePreferenceController implements Preference.OnPreferenceChangeListener {
private final CharSequence[] mEntryList;
private final String mPreferenceTitle;
private final String mPreferenceDefault;
private final String mPreferenceGup;
private final String mPreferenceNative;
private final List<AppInfo> mAppInfos;
private final Set<String> mDevOptInApps;
private final Set<String> mDevOptOutApps;
public GupPreferenceController(Context context, String key) {
super(context, key);
final Resources resources = context.getResources();
mEntryList = resources.getStringArray(R.array.gup_app_preference_values);
mPreferenceTitle = resources.getString(R.string.gup_app_preference_title);
mPreferenceDefault = resources.getString(R.string.gup_app_preference_default);
mPreferenceGup = resources.getString(R.string.gup_app_preference_gup);
mPreferenceNative = resources.getString(R.string.gup_app_preference_native);
// TODO: Move this task to background if there's potential ANR/Jank.
// Update the UI when all the app infos are ready.
mAppInfos = getAppInfos(context);
final ContentResolver contentResolver = context.getContentResolver();
mDevOptInApps =
getGlobalSettingsString(contentResolver, Settings.Global.GUP_DEV_OPT_IN_APPS);
mDevOptOutApps =
getGlobalSettingsString(contentResolver, Settings.Global.GUP_DEV_OPT_OUT_APPS);
}
@Override
public int getAvailabilityStatus() {
return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext)
? AVAILABLE
: DISABLED_DEPENDENT_SETTING;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
final PreferenceGroup preferenceGroup =
(PreferenceGroup) screen.findPreference(getPreferenceKey());
if (preferenceGroup == null) {
return;
}
for (AppInfo appInfo : mAppInfos) {
preferenceGroup.addPreference(
createListPreference(appInfo.info.packageName, appInfo.label));
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
final ListPreference listPref = (ListPreference) preference;
final String value = newValue.toString();
final String packageName = preference.getKey();
// When user choose a new preference, update both Sets for
// opt-in and opt-out apps. Then set the new summary text.
if (value.equals(mPreferenceNative)) {
mDevOptInApps.remove(packageName);
mDevOptOutApps.add(packageName);
listPref.setSummary(mPreferenceNative);
} else if (value.equals(mPreferenceGup)) {
mDevOptInApps.add(packageName);
mDevOptOutApps.remove(packageName);
listPref.setSummary(mPreferenceGup);
} else {
mDevOptInApps.remove(packageName);
mDevOptOutApps.remove(packageName);
listPref.setSummary(mPreferenceDefault);
}
// Push the updated Sets for opt-in and opt-out apps to
// corresponding Settings.Global.GUP_DEV_OPT_(IN|OUT)_APPS
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.GUP_DEV_OPT_IN_APPS, String.join(",", mDevOptInApps));
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.GUP_DEV_OPT_OUT_APPS, String.join(",", mDevOptOutApps));
return true;
}
// AppInfo class to achieve loading the application label only once
class AppInfo {
AppInfo(PackageManager packageManager, ApplicationInfo applicationInfo) {
info = applicationInfo;
label = packageManager.getApplicationLabel(applicationInfo).toString();
}
final ApplicationInfo info;
final String label;
}
// List of non-system packages that are installed for the current user.
private List<AppInfo> getAppInfos(Context context) {
final PackageManager packageManager = context.getPackageManager();
final List<ApplicationInfo> applicationInfos =
packageManager.getInstalledApplications(0 /* flags */);
final List<AppInfo> appInfos = new ArrayList<>();
for (ApplicationInfo applicationInfo : applicationInfos) {
if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
appInfos.add(new AppInfo(packageManager, applicationInfo));
}
}
Collections.sort(appInfos, appInfoComparator);
return appInfos;
}
// Parse the raw comma separated package names into a String Set
private Set<String> getGlobalSettingsString(ContentResolver contentResolver, String name) {
final String settingsValue = Settings.Global.getString(contentResolver, name);
if (settingsValue == null) {
return new HashSet<>();
}
final Set<String> valueSet = new HashSet<>(Arrays.asList(settingsValue.split(",")));
valueSet.remove("");
return valueSet;
}
private final Comparator<AppInfo> appInfoComparator = new Comparator<AppInfo>() {
public final int compare(AppInfo a, AppInfo b) {
return Collator.getInstance().compare(a.label, b.label);
}
};
@VisibleForTesting
protected ListPreference createListPreference(String packageName, String appName) {
final ListPreference listPreference = new ListPreference(mContext);
listPreference.setKey(packageName);
listPreference.setTitle(appName);
listPreference.setDialogTitle(mPreferenceTitle);
listPreference.setEntries(mEntryList);
listPreference.setEntryValues(mEntryList);
// Initialize preference default and summary with the opt in/out choices
// from Settings.Global.GUP_DEV_OPT_(IN|OUT)_APPS
if (mDevOptOutApps.contains(packageName)) {
listPreference.setValue(mPreferenceNative);
listPreference.setSummary(mPreferenceNative);
} else if (mDevOptInApps.contains(packageName)) {
listPreference.setValue(mPreferenceGup);
listPreference.setSummary(mPreferenceGup);
} else {
listPreference.setValue(mPreferenceDefault);
listPreference.setSummary(mPreferenceDefault);
}
listPreference.setOnPreferenceChangeListener(this);
return listPreference;
}
}

View File

@@ -28,7 +28,6 @@ com.android.settings.bluetooth.DevicePickerFragment
com.android.settings.datausage.AppDataUsage com.android.settings.datausage.AppDataUsage
com.android.settings.datausage.DataUsageList com.android.settings.datausage.DataUsageList
com.android.settings.datetime.timezone.TimeZoneSettings com.android.settings.datetime.timezone.TimeZoneSettings
com.android.settings.development.gup.GupDashboard
com.android.settings.deviceinfo.PrivateVolumeSettings com.android.settings.deviceinfo.PrivateVolumeSettings
com.android.settings.deviceinfo.PublicVolumeSettings com.android.settings.deviceinfo.PublicVolumeSettings
com.android.settings.deviceinfo.StorageProfileFragment com.android.settings.deviceinfo.StorageProfileFragment

View File

@@ -1,133 +0,0 @@
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.development;
import static com.android.settings.development.DevelopmentOptionsActivityRequestCodes.REQUEST_CODE_GUP_DEV_OPT_IN_APPS;
import static com.google.common.truth.Truth.assertThat;
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.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.provider.Settings;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
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;
@RunWith(RobolectricTestRunner.class)
public class GameUpdatePackageDevOptInPreferenceControllerTest {
@Mock
private PreferenceScreen mPreferenceScreen;
@Mock
private DevelopmentSettingsDashboardFragment mFragment;
private Context mContext;
private Preference mPreference;
private GameUpdatePackageDevOptInPreferenceController mController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mController = spy(new GameUpdatePackageDevOptInPreferenceController(mContext, mFragment));
mPreference = new Preference(mContext);
mPreference.setKey(mController.getPreferenceKey());
when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
.thenReturn(mPreference);
mController.displayPreference(mPreferenceScreen);
}
@Test
public void handlePreferenceTreeClick_preferenceClicked_launchActivity() {
final Intent activityStartIntent = new Intent(mContext, AppPicker.class);
doReturn(activityStartIntent).when(mController).getActivityStartIntent();
mController.handlePreferenceTreeClick(mPreference);
verify(mFragment).startActivityForResult(activityStartIntent,
REQUEST_CODE_GUP_DEV_OPT_IN_APPS);
}
@Test
public void updateState_foobarAppSelected_shouldUpdateSummaryWithGUPDevOptInAppLabel() {
final String selectedApp = "foobar";
final ContentResolver contentResolver = mContext.getContentResolver();
Settings.Global.putString(contentResolver,
Settings.Global.GUP_DEV_OPT_IN_APPS, selectedApp);
mController.updateState(mPreference);
assertThat(mPreference.getSummary()).isEqualTo(
mContext.getString(R.string.gup_dev_opt_in_app_set, selectedApp));
}
@Test
public void updateState_noAppSelected_shouldUpdateSummaryWithNoAppSelected() {
final String selectedApp = null;
final ContentResolver contentResolver = mContext.getContentResolver();
Settings.Global.putString(contentResolver,
Settings.Global.GUP_DEV_OPT_IN_APPS, selectedApp);
mController.updateState(mPreference);
assertThat(mPreference.getSummary()).isEqualTo(
mContext.getString(R.string.gup_dev_opt_in_app_not_set));
}
@Test
public void onActivityResult_foobarAppSelected_shouldUpdateSummaryWithGUPDevOptInLabel() {
Intent activityResultIntent = new Intent(mContext, AppPicker.class);
final String appLabel = "foobar";
activityResultIntent.setAction(appLabel);
final boolean result = mController
.onActivityResult(REQUEST_CODE_GUP_DEV_OPT_IN_APPS, Activity.RESULT_OK,
activityResultIntent);
assertThat(result).isTrue();
assertThat(mPreference.getSummary()).isEqualTo(
mContext.getString(R.string.gup_dev_opt_in_app_set, appLabel));
}
@Test
public void onActivityResult_badRequestCode_shouldReturnFalse() {
assertThat(mController.onActivityResult(
-1 /* requestCode */, -1 /* resultCode */, null /* intent */)).isFalse();
}
@Test
public void onDeveloperOptionsSwitchDisabled_shouldDisablePreference() {
mController.onDeveloperOptionsSwitchDisabled();
assertThat(mPreference.isEnabled()).isFalse();
assertThat(mPreference.getSummary()).isEqualTo(
mContext.getString(R.string.gup_dev_opt_in_app_not_set));
}
}

View File

@@ -0,0 +1,231 @@
/*
* Copyright 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.gup;
import static com.android.settings.core.BasePreferenceController.AVAILABLE;
import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING;
import static com.android.settings.testutils.ApplicationTestUtils.buildInfo;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.provider.Settings;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import java.util.Arrays;
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;
@RunWith(RobolectricTestRunner.class)
public class GupPreferenceControllerTest {
private static final int DEFAULT = 0;
private static final int GUP = 1;
private static final int NATIVE = 2;
private static final String TEST_APP_NAME = "testApp";
private static final String TEST_PKG_NAME = "testPkg";
// Pre-installed Apps in the Mock PackageManager
private static final String APP_1 = "app1";
private static final String APP_2 = "app2";
private static final String APP_3 = "app3";
@Mock
private PackageManager mPackageManager;
@Mock
private PreferenceScreen mScreen;
private Context mContext;
private PreferenceGroup mGroup;
private PreferenceManager mPreferenceManager;
private ContentResolver mResolver;
private GupPreferenceController mController;
private CharSequence[] mValueList;
private String mDialogTitle;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application);
mResolver = mContext.getContentResolver();
mValueList = mContext.getResources().getStringArray(R.array.gup_app_preference_values);
mDialogTitle = mContext.getResources().getString(R.string.gup_app_preference_title);
}
@Test
public void getAvailability_developmentSettingsEnabled_available() {
loadDefaultConfig();
Settings.Global.putInt(mResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
}
@Test
public void getAvailability_developmentSettingsDisabled_disabledDependentSetting() {
loadDefaultConfig();
Settings.Global.putInt(mResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0);
assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING);
}
@Test
public void displayPreference_shouldAddTwoPreferencesAndSortAscendingly() {
mockPackageManager();
loadDefaultConfig();
// Only non-system app has preference
assertThat(mGroup.getPreferenceCount()).isEqualTo(2);
assertThat(mGroup.getPreference(0).getKey()).isEqualTo(APP_1);
assertThat(mGroup.getPreference(1).getKey()).isEqualTo(APP_3);
}
@Test
public void createPreference_configDefault_shouldSetDefaultAttributes() {
loadDefaultConfig();
final ListPreference preference =
mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
assertThat(preference.getKey()).isEqualTo(TEST_PKG_NAME);
assertThat(preference.getTitle()).isEqualTo(TEST_APP_NAME);
assertThat(preference.getDialogTitle()).isEqualTo(mDialogTitle);
assertThat(preference.getEntries()).isEqualTo(mValueList);
assertThat(preference.getEntryValues()).isEqualTo(mValueList);
assertThat(preference.getEntry()).isEqualTo(mValueList[DEFAULT]);
assertThat(preference.getValue()).isEqualTo(mValueList[DEFAULT]);
assertThat(preference.getSummary()).isEqualTo(mValueList[DEFAULT]);
}
@Test
public void createPreference_configGup_shouldSetGupAttributes() {
loadConfig(TEST_PKG_NAME, "");
final ListPreference preference =
mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
assertThat(preference.getKey()).isEqualTo(TEST_PKG_NAME);
assertThat(preference.getTitle()).isEqualTo(TEST_APP_NAME);
assertThat(preference.getDialogTitle()).isEqualTo(mDialogTitle);
assertThat(preference.getEntries()).isEqualTo(mValueList);
assertThat(preference.getEntryValues()).isEqualTo(mValueList);
assertThat(preference.getEntry()).isEqualTo(mValueList[GUP]);
assertThat(preference.getValue()).isEqualTo(mValueList[GUP]);
assertThat(preference.getSummary()).isEqualTo(mValueList[GUP]);
}
@Test
public void createPreference_configNative_shouldSetNativeAttributes() {
loadConfig("", TEST_PKG_NAME);
final ListPreference preference =
mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
assertThat(preference.getKey()).isEqualTo(TEST_PKG_NAME);
assertThat(preference.getTitle()).isEqualTo(TEST_APP_NAME);
assertThat(preference.getDialogTitle()).isEqualTo(mDialogTitle);
assertThat(preference.getEntries()).isEqualTo(mValueList);
assertThat(preference.getEntryValues()).isEqualTo(mValueList);
assertThat(preference.getEntry()).isEqualTo(mValueList[NATIVE]);
assertThat(preference.getValue()).isEqualTo(mValueList[NATIVE]);
assertThat(preference.getSummary()).isEqualTo(mValueList[NATIVE]);
}
@Test
public void onPreferenceChange_selectDefault_shouldUpdateAttributesAndSettingsGlobal() {
loadDefaultConfig();
final ListPreference preference =
mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
mController.onPreferenceChange(preference, mValueList[DEFAULT]);
assertThat(preference.getSummary()).isEqualTo(mValueList[DEFAULT]);
assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_IN_APPS))
.isEqualTo("");
assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_OUT_APPS))
.isEqualTo("");
}
@Test
public void onPreferenceChange_selectGup_shouldUpdateAttributesAndSettingsGlobal() {
loadDefaultConfig();
final ListPreference preference =
mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
mController.onPreferenceChange(preference, mValueList[GUP]);
assertThat(preference.getSummary()).isEqualTo(mValueList[GUP]);
assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_IN_APPS))
.isEqualTo(TEST_PKG_NAME);
assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_OUT_APPS))
.isEqualTo("");
}
@Test
public void onPreferenceChange_selectNative_shouldUpdateAttributesAndSettingsGlobal() {
loadDefaultConfig();
final ListPreference preference =
mController.createListPreference(TEST_PKG_NAME, TEST_APP_NAME);
mController.onPreferenceChange(preference, mValueList[NATIVE]);
assertThat(preference.getSummary()).isEqualTo(mValueList[NATIVE]);
assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_IN_APPS))
.isEqualTo("");
assertThat(Settings.Global.getString(mResolver, Settings.Global.GUP_DEV_OPT_OUT_APPS))
.isEqualTo(TEST_PKG_NAME);
}
private void mockPackageManager() {
final int uid = mContext.getUserId();
final ApplicationInfo app1 = buildInfo(uid, APP_1, 0 /* flags */, 0 /* targetSdkVersion */);
final ApplicationInfo app2 =
buildInfo(uid, APP_2, ApplicationInfo.FLAG_SYSTEM, 0 /* targetSdkVersion */);
final ApplicationInfo app3 = buildInfo(uid, APP_3, 0 /* flags */, 0 /* targetSdkVersion */);
when(mPackageManager.getInstalledApplications(0 /* flags */))
.thenReturn(Arrays.asList(app3, app2, app1));
when(mPackageManager.getApplicationLabel(app1)).thenReturn(APP_1);
when(mPackageManager.getApplicationLabel(app2)).thenReturn(APP_2);
when(mPackageManager.getApplicationLabel(app3)).thenReturn(APP_3);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
}
private void loadDefaultConfig() { loadConfig("", ""); }
private void loadConfig(String optIn, String optOut) {
Settings.Global.putString(mResolver, Settings.Global.GUP_DEV_OPT_IN_APPS, optIn);
Settings.Global.putString(mResolver, Settings.Global.GUP_DEV_OPT_OUT_APPS, optOut);
mController = new GupPreferenceController(mContext, "testKey");
mGroup = spy(new PreferenceCategory(mContext));
final PreferenceManager preferenceManager = new PreferenceManager(mContext);
when(mGroup.getPreferenceManager()).thenReturn(preferenceManager);
when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mGroup);
mController.displayPreference(mScreen);
}
}