diff --git a/res/values/strings.xml b/res/values/strings.xml index 62c36c2e409..b9ff512639b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -9982,12 +9982,28 @@ show both names, with the directory name wrapped in parenthesis --> %1$s (%2$s) - - Use Game Update Package - - No selected app - - %1$s + + Game Driver Preferences + + Modify Game Driver settings + + When Game Driver is turned on, you can pick to use the updated graphics driver for Apps installed on the device. + + Enable for all apps + + Select Graphics Driver + + Default + + Game Driver + + System Graphics Driver + + + @string/game_driver_app_preference_default + @string/game_driver_app_preference_game_driver + @string/game_driver_app_preference_system + diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml index 7a98f13c888..cde55433ab1 100644 --- a/res/xml/development_settings.xml +++ b/res/xml/development_settings.xml @@ -197,6 +197,12 @@ android:title="@string/enable_gpu_debug_layers" android:summary="@string/enable_gpu_debug_layers_summary" /> + + - - + + + + + + + + + + + + + + diff --git a/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java b/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java index a7bce1451f4..b7b27591df9 100644 --- a/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java +++ b/src/com/android/settings/development/DevelopmentOptionsActivityRequestCodes.java @@ -25,6 +25,4 @@ public interface DevelopmentOptionsActivityRequestCodes { int REQUEST_CODE_DEBUG_APP = 1; int REQUEST_MOCK_LOCATION_APP = 2; - - int REQUEST_CODE_GUP_DEV_OPT_IN_APPS = 6; } diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index 575e8fe1ca2..8518c7446eb 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -400,7 +400,6 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra controllers.add(new SelectDebugAppPreferenceController(context, fragment)); controllers.add(new WaitForDebuggerPreferenceController(context)); controllers.add(new EnableGpuDebugLayersPreferenceController(context)); - controllers.add(new GameUpdatePackageDevOptInPreferenceController(context, fragment)); controllers.add(new VerifyAppsOverUsbPreferenceController(context)); controllers.add(new LogdSizePreferenceController(context)); controllers.add(new LogPersistPreferenceController(context, fragment, lifecycle)); diff --git a/src/com/android/settings/development/GameUpdatePackageDevOptInPreferenceController.java b/src/com/android/settings/development/GameUpdatePackageDevOptInPreferenceController.java deleted file mode 100644 index be2c7a5dac8..00000000000 --- a/src/com/android/settings/development/GameUpdatePackageDevOptInPreferenceController.java +++ /dev/null @@ -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_DEBUGGABLE, 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; - } - } -} diff --git a/src/com/android/settings/development/gamedriver/GameDriverAppPreferenceController.java b/src/com/android/settings/development/gamedriver/GameDriverAppPreferenceController.java new file mode 100644 index 00000000000..659310c2580 --- /dev/null +++ b/src/com/android/settings/development/gamedriver/GameDriverAppPreferenceController.java @@ -0,0 +1,259 @@ +/* + * 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.gamedriver; + +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT; +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF; + +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.os.Handler; +import android.os.Looper; +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.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; +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; + +/** + * Controller of all the per App based list preferences. + */ +public class GameDriverAppPreferenceController extends BasePreferenceController + implements Preference.OnPreferenceChangeListener, + GameDriverContentObserver.OnGameDriverContentChangedListener, LifecycleObserver, + OnStart, OnStop { + + private final Context mContext; + private final ContentResolver mContentResolver; + private final CharSequence[] mEntryList; + private final String mPreferenceTitle; + private final String mPreferenceDefault; + private final String mPreferenceGameDriver; + private final String mPreferenceSystem; + @VisibleForTesting + GameDriverContentObserver mGameDriverContentObserver; + + private final List mAppInfos; + private final Set mDevOptInApps; + private final Set mDevOptOutApps; + + private PreferenceGroup mPreferenceGroup; + + public GameDriverAppPreferenceController(Context context, String key) { + super(context, key); + + mContext = context; + mContentResolver = context.getContentResolver(); + mGameDriverContentObserver = + new GameDriverContentObserver(new Handler(Looper.getMainLooper()), this); + + final Resources resources = context.getResources(); + mEntryList = resources.getStringArray(R.array.game_driver_app_preference_values); + mPreferenceTitle = resources.getString(R.string.game_driver_app_preference_title); + mPreferenceDefault = resources.getString(R.string.game_driver_app_preference_default); + mPreferenceGameDriver = + resources.getString(R.string.game_driver_app_preference_game_driver); + mPreferenceSystem = resources.getString(R.string.game_driver_app_preference_system); + + // 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); + + mDevOptInApps = + getGlobalSettingsString(mContentResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS); + mDevOptOutApps = + getGlobalSettingsString(mContentResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS); + } + + @Override + public int getAvailabilityStatus() { + return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext) + && (Settings.Global.getInt(mContentResolver, + Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT) + != GAME_DRIVER_OFF) + ? AVAILABLE + : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreferenceGroup = (PreferenceGroup) screen.findPreference(getPreferenceKey()); + + final Context context = mPreferenceGroup.getContext(); + for (AppInfo appInfo : mAppInfos) { + mPreferenceGroup.addPreference( + createListPreference(context, appInfo.info.packageName, appInfo.label)); + } + } + + @Override + public void onStart() { + mGameDriverContentObserver.register(mContentResolver); + } + + @Override + public void onStop() { + mGameDriverContentObserver.unregister(mContentResolver); + } + + @Override + public void updateState(Preference preference) { + // This is a workaround, because PreferenceGroup.setVisible is not applied to the + // preferences inside the group. + final boolean isGroupAvailable = isAvailable(); + final PreferenceGroup group = (PreferenceGroup) preference; + for (int idx = 0; idx < group.getPreferenceCount(); idx++) { + final Preference pref = group.getPreference(idx); + pref.setVisible(isGroupAvailable); + } + preference.setVisible(isGroupAvailable); + } + + @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(mPreferenceSystem)) { + mDevOptInApps.remove(packageName); + mDevOptOutApps.add(packageName); + } else if (value.equals(mPreferenceGameDriver)) { + mDevOptInApps.add(packageName); + mDevOptOutApps.remove(packageName); + } else { + mDevOptInApps.remove(packageName); + mDevOptOutApps.remove(packageName); + } + listPref.setValue(value); + listPref.setSummary(value); + + // Push the updated Sets for opt-in and opt-out apps to + // corresponding Settings.Global.GAME_DRIVER_OPT_(IN|OUT)_APPS + Settings.Global.putString(mContentResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS, + String.join(",", mDevOptInApps)); + Settings.Global.putString(mContentResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS, + String.join(",", mDevOptOutApps)); + + return true; + } + + @Override + public void onGameDriverContentChanged() { + updateState(mPreferenceGroup); + } + + // 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 getAppInfos(Context context) { + final PackageManager packageManager = context.getPackageManager(); + final List applicationInfos = + packageManager.getInstalledApplications(0 /* flags */); + + final List 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 getGlobalSettingsString(ContentResolver contentResolver, String name) { + final String settingsValue = Settings.Global.getString(contentResolver, name); + if (settingsValue == null) { + return new HashSet<>(); + } + + final Set valueSet = new HashSet<>(Arrays.asList(settingsValue.split(","))); + valueSet.remove(""); + + return valueSet; + } + + private final Comparator appInfoComparator = new Comparator() { + public final int compare(AppInfo a, AppInfo b) { + return Collator.getInstance().compare(a.label, b.label); + } + }; + + @VisibleForTesting + protected ListPreference createListPreference( + Context context, String packageName, String appName) { + final ListPreference listPreference = new ListPreference(context); + + 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.GAME_DRIVER_OPT_(IN|OUT)_APPS + if (mDevOptOutApps.contains(packageName)) { + listPreference.setValue(mPreferenceSystem); + listPreference.setSummary(mPreferenceSystem); + } else if (mDevOptInApps.contains(packageName)) { + listPreference.setValue(mPreferenceGameDriver); + listPreference.setSummary(mPreferenceGameDriver); + } else { + listPreference.setValue(mPreferenceDefault); + listPreference.setSummary(mPreferenceDefault); + } + + listPreference.setOnPreferenceChangeListener(this); + + return listPreference; + } +} diff --git a/src/com/android/settings/development/gamedriver/GameDriverContentObserver.java b/src/com/android/settings/development/gamedriver/GameDriverContentObserver.java new file mode 100644 index 00000000000..e31e04640b3 --- /dev/null +++ b/src/com/android/settings/development/gamedriver/GameDriverContentObserver.java @@ -0,0 +1,57 @@ +/* + * 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.gamedriver; + +import android.content.ContentResolver; +import android.database.ContentObserver; +import android.os.Handler; +import android.provider.Settings; + +import androidx.annotation.VisibleForTesting; + +/** + * Helper class to observe Game Driver settings global change. + */ +public class GameDriverContentObserver extends ContentObserver { + + interface OnGameDriverContentChangedListener { + void onGameDriverContentChanged(); + } + + @VisibleForTesting + OnGameDriverContentChangedListener mListener; + + public GameDriverContentObserver(Handler handler, OnGameDriverContentChangedListener listener) { + super(handler); + mListener = listener; + } + + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + mListener.onGameDriverContentChanged(); + } + + public void register(ContentResolver contentResolver) { + contentResolver.registerContentObserver( + Settings.Global.getUriFor(Settings.Global.GAME_DRIVER_ALL_APPS), false, this); + } + + public void unregister(ContentResolver contentResolver) { + contentResolver.unregisterContentObserver(this); + } +} diff --git a/src/com/android/settings/development/gamedriver/GameDriverDashboard.java b/src/com/android/settings/development/gamedriver/GameDriverDashboard.java new file mode 100644 index 00000000000..b79af719996 --- /dev/null +++ b/src/com/android/settings/development/gamedriver/GameDriverDashboard.java @@ -0,0 +1,70 @@ +/* + * 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.gamedriver; + +import android.content.Context; +import android.os.Bundle; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.SettingsActivity; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.widget.SwitchBar; +import com.android.settings.widget.SwitchBarController; + +import java.util.List; + +/** + * Dashboard for Game Driver preferences. + */ +public class GameDriverDashboard extends DashboardFragment { + + private static final String TAG = "GameDriverDashboard"; + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.SETTINGS_GAME_DRIVER_DASHBOARD; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.game_driver_settings; + } + + @Override + public int getHelpResource() { + return 0; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + final SettingsActivity activity = (SettingsActivity) getActivity(); + final SwitchBar switchBar = activity.getSwitchBar(); + final GameDriverGlobalSwitchBarController switchBarController = + new GameDriverGlobalSwitchBarController( + activity, new SwitchBarController(switchBar)); + getLifecycle().addObserver(switchBarController); + switchBar.show(); + } +} diff --git a/src/com/android/settings/development/gamedriver/GameDriverEnableForAllAppsPreferenceController.java b/src/com/android/settings/development/gamedriver/GameDriverEnableForAllAppsPreferenceController.java new file mode 100644 index 00000000000..7f9b74b80b0 --- /dev/null +++ b/src/com/android/settings/development/gamedriver/GameDriverEnableForAllAppsPreferenceController.java @@ -0,0 +1,124 @@ +/* + * 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.gamedriver; + +import android.content.ContentResolver; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; +import com.android.settingslib.development.DevelopmentSettingsEnabler; + +/** + * Controller of global switch to enable Game Driver for all Apps. + */ +public class GameDriverEnableForAllAppsPreferenceController extends BasePreferenceController + implements Preference.OnPreferenceChangeListener, + GameDriverContentObserver.OnGameDriverContentChangedListener, LifecycleObserver, + OnStart, OnStop { + + public static final int GAME_DRIVER_DEFAULT = 0; + public static final int GAME_DRIVER_ALL_APPS = 1; + public static final int GAME_DRIVER_OFF = 2; + + private final Context mContext; + private final ContentResolver mContentResolver; + @VisibleForTesting + GameDriverContentObserver mGameDriverContentObserver; + + private SwitchPreference mPreference; + + public GameDriverEnableForAllAppsPreferenceController(Context context, String key) { + super(context, key); + mContext = context; + mContentResolver = context.getContentResolver(); + mGameDriverContentObserver = + new GameDriverContentObserver(new Handler(Looper.getMainLooper()), this); + } + + @Override + public int getAvailabilityStatus() { + return DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(mContext) + && (Settings.Global.getInt(mContentResolver, + Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT) + != GAME_DRIVER_OFF) + ? AVAILABLE + : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = (SwitchPreference) screen.findPreference(getPreferenceKey()); + mPreference.setOnPreferenceChangeListener(this); + } + + @Override + public void onStart() { + mGameDriverContentObserver.register(mContentResolver); + } + + @Override + public void onStop() { + mGameDriverContentObserver.unregister(mContentResolver); + } + + @Override + public void updateState(Preference preference) { + final SwitchPreference switchPreference = (SwitchPreference) preference; + switchPreference.setVisible(isAvailable()); + switchPreference.setChecked( + Settings.Global.getInt( + mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT) + == GAME_DRIVER_ALL_APPS); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final boolean isChecked = (boolean) newValue; + final int gameDriver = Settings.Global.getInt( + mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT); + + if (isChecked && gameDriver == GAME_DRIVER_ALL_APPS) { + return true; + } + + if (!isChecked && (gameDriver == GAME_DRIVER_DEFAULT || gameDriver == GAME_DRIVER_OFF)) { + return true; + } + + Settings.Global.putInt(mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, + isChecked ? GAME_DRIVER_ALL_APPS : GAME_DRIVER_DEFAULT); + + return true; + } + + @Override + public void onGameDriverContentChanged() { + updateState(mPreference); + } +} diff --git a/src/com/android/settings/development/gamedriver/GameDriverFooterPreferenceController.java b/src/com/android/settings/development/gamedriver/GameDriverFooterPreferenceController.java new file mode 100644 index 00000000000..bacbf95fa3b --- /dev/null +++ b/src/com/android/settings/development/gamedriver/GameDriverFooterPreferenceController.java @@ -0,0 +1,92 @@ +/* + * 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.gamedriver; + +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT; +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF; + +import android.content.ContentResolver; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.core.BasePreferenceController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; +import com.android.settingslib.widget.FooterPreference; + +/** + * Controller of footer preference for Game Driver. + */ +public class GameDriverFooterPreferenceController extends BasePreferenceController + implements GameDriverContentObserver.OnGameDriverContentChangedListener, LifecycleObserver, + OnStart, OnStop { + + private final ContentResolver mContentResolver; + @VisibleForTesting + GameDriverContentObserver mGameDriverContentObserver; + + private FooterPreference mPreference; + + public GameDriverFooterPreferenceController(Context context) { + super(context, FooterPreference.KEY_FOOTER); + mContentResolver = context.getContentResolver(); + mGameDriverContentObserver = + new GameDriverContentObserver(new Handler(Looper.getMainLooper()), this); + } + + @Override + public int getAvailabilityStatus() { + return Settings.Global.getInt( + mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT) + == GAME_DRIVER_OFF + ? AVAILABLE + : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = (FooterPreference) screen.findPreference(getPreferenceKey()); + } + + @Override + public void onStart() { + mGameDriverContentObserver.register(mContentResolver); + } + + @Override + public void onStop() { + mGameDriverContentObserver.unregister(mContentResolver); + } + + @Override + public void updateState(Preference preference) { + preference.setVisible(isAvailable()); + } + + @Override + public void onGameDriverContentChanged() { + updateState(mPreference); + } +} diff --git a/src/com/android/settings/development/gamedriver/GameDriverGlobalSwitchBarController.java b/src/com/android/settings/development/gamedriver/GameDriverGlobalSwitchBarController.java new file mode 100644 index 00000000000..d84c28f3f5b --- /dev/null +++ b/src/com/android/settings/development/gamedriver/GameDriverGlobalSwitchBarController.java @@ -0,0 +1,107 @@ +/* + * 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.gamedriver; + +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_ALL_APPS; +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT; +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF; + +import android.content.ContentResolver; +import android.content.Context; +import android.os.Handler; +import android.os.Looper; +import android.provider.Settings; + +import androidx.annotation.VisibleForTesting; + +import com.android.settings.widget.SwitchWidgetController; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; +import com.android.settingslib.development.DevelopmentSettingsEnabler; + +/** + * Controller of global switch bar used to fully turn off Game Driver. + */ +public class GameDriverGlobalSwitchBarController + implements SwitchWidgetController.OnSwitchChangeListener, + GameDriverContentObserver.OnGameDriverContentChangedListener, LifecycleObserver, + OnStart, OnStop { + + private final Context mContext; + private final ContentResolver mContentResolver; + @VisibleForTesting + SwitchWidgetController mSwitchWidgetController; + @VisibleForTesting + GameDriverContentObserver mGameDriverContentObserver; + + GameDriverGlobalSwitchBarController( + Context context, SwitchWidgetController switchWidgetController) { + mContext = context; + mContentResolver = context.getContentResolver(); + mGameDriverContentObserver = + new GameDriverContentObserver(new Handler(Looper.getMainLooper()), this); + mSwitchWidgetController = switchWidgetController; + mSwitchWidgetController.setEnabled( + DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(context)); + mSwitchWidgetController.setChecked( + Settings.Global.getInt( + mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT) + != GAME_DRIVER_OFF); + mSwitchWidgetController.setListener(this); + } + + @Override + public void onStart() { + mSwitchWidgetController.startListening(); + mGameDriverContentObserver.register(mContentResolver); + } + + @Override + public void onStop() { + mSwitchWidgetController.stopListening(); + mGameDriverContentObserver.unregister(mContentResolver); + } + + @Override + public boolean onSwitchToggled(boolean isChecked) { + final int gameDriver = Settings.Global.getInt( + mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT); + + if (isChecked + && (gameDriver == GAME_DRIVER_DEFAULT || gameDriver == GAME_DRIVER_ALL_APPS)) { + return true; + } + + if (!isChecked && gameDriver == GAME_DRIVER_OFF) { + return true; + } + + Settings.Global.putInt(mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, + isChecked ? GAME_DRIVER_DEFAULT : GAME_DRIVER_OFF); + + return true; + } + + @Override + public void onGameDriverContentChanged() { + mSwitchWidgetController.setChecked( + Settings.Global.getInt( + mContentResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT) + != GAME_DRIVER_OFF); + } +} diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider index 39e63d4baa7..ffdaca8bda6 100644 --- a/tests/robotests/assets/grandfather_not_implementing_index_provider +++ b/tests/robotests/assets/grandfather_not_implementing_index_provider @@ -6,6 +6,7 @@ com.android.settings.accounts.AccountDetailDashboardFragment com.android.settings.fuelgauge.PowerUsageAnomalyDetails com.android.settings.fuelgauge.AdvancedPowerUsageDetail com.android.settings.development.featureflags.FeatureFlagsDashboard +com.android.settings.development.gamedriver.GameDriverDashboard com.android.settings.development.qstile.DevelopmentTileConfigFragment com.android.settings.deviceinfo.StorageProfileFragment com.android.settings.notification.ChannelNotificationSettings diff --git a/tests/robotests/src/com/android/settings/development/GameUpdatePackageDevOptInPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/GameUpdatePackageDevOptInPreferenceControllerTest.java deleted file mode 100644 index 84fa525d70b..00000000000 --- a/tests/robotests/src/com/android/settings/development/GameUpdatePackageDevOptInPreferenceControllerTest.java +++ /dev/null @@ -1,135 +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; -import org.robolectric.util.ReflectionHelpers; - -@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); - final String preferenceKey = mController.getPreferenceKey(); - 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)); - } -} diff --git a/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverAppPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverAppPreferenceControllerTest.java new file mode 100644 index 00000000000..5906cbc74f2 --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverAppPreferenceControllerTest.java @@ -0,0 +1,243 @@ +/* + * 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.gamedriver; + +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.verify; +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 GameDriverAppPreferenceControllerTest { + + private static final int DEFAULT = 0; + private static final int GAME_DRIVER = 1; + private static final int SYSTEM = 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; + @Mock + private GameDriverContentObserver mGameDriverContentObserver; + + private Context mContext; + private PreferenceGroup mGroup; + private PreferenceManager mPreferenceManager; + private ContentResolver mResolver; + private GameDriverAppPreferenceController 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.game_driver_app_preference_values); + mDialogTitle = mContext.getResources().getString(R.string.game_driver_app_preference_title); + } + + @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 onStart_shouldRegister() { + loadDefaultConfig(); + mController.mGameDriverContentObserver = mGameDriverContentObserver; + mController.onStart(); + + verify(mGameDriverContentObserver).register(mResolver); + } + + @Test + public void onStop_shouldUnregister() { + loadDefaultConfig(); + mController.mGameDriverContentObserver = mGameDriverContentObserver; + mController.onStop(); + + verify(mGameDriverContentObserver).unregister(mResolver); + } + + @Test + public void createPreference_configDefault_shouldSetDefaultAttributes() { + loadDefaultConfig(); + final ListPreference preference = + mController.createListPreference(mContext, 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_configGAME_DRIVER_shouldSetGameDriverAttributes() { + loadConfig(TEST_PKG_NAME, ""); + final ListPreference preference = + mController.createListPreference(mContext, 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[GAME_DRIVER]); + assertThat(preference.getValue()).isEqualTo(mValueList[GAME_DRIVER]); + assertThat(preference.getSummary()).isEqualTo(mValueList[GAME_DRIVER]); + } + + @Test + public void createPreference_configSystem_shouldSetSystemAttributes() { + loadConfig("", TEST_PKG_NAME); + final ListPreference preference = + mController.createListPreference(mContext, 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[SYSTEM]); + assertThat(preference.getValue()).isEqualTo(mValueList[SYSTEM]); + assertThat(preference.getSummary()).isEqualTo(mValueList[SYSTEM]); + } + + @Test + public void onPreferenceChange_selectDefault_shouldUpdateAttributesAndSettingsGlobal() { + loadDefaultConfig(); + final ListPreference preference = + mController.createListPreference(mContext, TEST_PKG_NAME, TEST_APP_NAME); + mController.onPreferenceChange(preference, mValueList[DEFAULT]); + + assertThat(preference.getEntry()).isEqualTo(mValueList[DEFAULT]); + assertThat(preference.getValue()).isEqualTo(mValueList[DEFAULT]); + assertThat(preference.getSummary()).isEqualTo(mValueList[DEFAULT]); + assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS)) + .isEqualTo(""); + assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS)) + .isEqualTo(""); + } + + @Test + public void onPreferenceChange_selectGAME_DRIVER_shouldUpdateAttributesAndSettingsGlobal() { + loadDefaultConfig(); + final ListPreference preference = + mController.createListPreference(mContext, TEST_PKG_NAME, TEST_APP_NAME); + mController.onPreferenceChange(preference, mValueList[GAME_DRIVER]); + + assertThat(preference.getEntry()).isEqualTo(mValueList[GAME_DRIVER]); + assertThat(preference.getValue()).isEqualTo(mValueList[GAME_DRIVER]); + assertThat(preference.getSummary()).isEqualTo(mValueList[GAME_DRIVER]); + assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS)) + .isEqualTo(TEST_PKG_NAME); + assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS)) + .isEqualTo(""); + } + + @Test + public void onPreferenceChange_selectSystem_shouldUpdateAttributesAndSettingsGlobal() { + loadDefaultConfig(); + final ListPreference preference = + mController.createListPreference(mContext, TEST_PKG_NAME, TEST_APP_NAME); + mController.onPreferenceChange(preference, mValueList[SYSTEM]); + + assertThat(preference.getEntry()).isEqualTo(mValueList[SYSTEM]); + assertThat(preference.getValue()).isEqualTo(mValueList[SYSTEM]); + assertThat(preference.getSummary()).isEqualTo(mValueList[SYSTEM]); + assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_OPT_IN_APPS)) + .isEqualTo(""); + assertThat(Settings.Global.getString(mResolver, Settings.Global.GAME_DRIVER_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.GAME_DRIVER_OPT_IN_APPS, optIn); + Settings.Global.putString(mResolver, Settings.Global.GAME_DRIVER_OPT_OUT_APPS, optOut); + + mController = new GameDriverAppPreferenceController(mContext, "testKey"); + mGroup = spy(new PreferenceCategory(mContext)); + final PreferenceManager preferenceManager = new PreferenceManager(mContext); + when(mGroup.getContext()).thenReturn(mContext); + when(mGroup.getPreferenceManager()).thenReturn(preferenceManager); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mGroup); + mController.displayPreference(mScreen); + } +} diff --git a/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverContentObserverTest.java b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverContentObserverTest.java new file mode 100644 index 00000000000..caaf896f5fc --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverContentObserverTest.java @@ -0,0 +1,72 @@ +/* + * 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.gamedriver; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.ContentResolver; +import android.provider.Settings; + +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 GameDriverContentObserverTest { + + @Mock + private ContentResolver mResolver; + @Mock + private GameDriverContentObserver.OnGameDriverContentChangedListener mListener; + + private GameDriverContentObserver mGameDriverContentObserver; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mGameDriverContentObserver = spy(new GameDriverContentObserver(null, null)); + } + + @Test + public void onChange_shouldCallListener() { + mGameDriverContentObserver.mListener = mListener; + mGameDriverContentObserver.onChange(true); + + verify(mListener).onGameDriverContentChanged(); + } + + @Test + public void register_shouldRegisterContentObserver() { + mGameDriverContentObserver.register(mResolver); + + verify(mResolver).registerContentObserver( + Settings.Global.getUriFor(Settings.Global.GAME_DRIVER_ALL_APPS), false, + mGameDriverContentObserver); + } + + @Test + public void unregister_shouldUnregisterContentObserver() { + mGameDriverContentObserver.unregister(mResolver); + + verify(mResolver).unregisterContentObserver(mGameDriverContentObserver); + } +} diff --git a/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverDashboardTest.java b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverDashboardTest.java new file mode 100644 index 00000000000..29e74148544 --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverDashboardTest.java @@ -0,0 +1,55 @@ +/* + * 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.gamedriver; + +import static com.google.common.truth.Truth.assertThat; + +import com.android.internal.logging.nano.MetricsProto; + +import com.android.settings.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +@RunWith(RobolectricTestRunner.class) +public class GameDriverDashboardTest { + + private GameDriverDashboard mDashboard; + + @Before + public void setUp() { + mDashboard = new GameDriverDashboard(); + } + + @Test + public void getHelpResource_shouldReturn0() { + assertThat(mDashboard.getHelpResource()).isEqualTo(0); + } + + @Test + public void getMetricesCategory_shouldReturnGameDriverDashboard() { + assertThat(mDashboard.getMetricsCategory()) + .isEqualTo(MetricsProto.MetricsEvent.SETTINGS_GAME_DRIVER_DASHBOARD); + } + + @Test + public void getPreferenceScreen_shouldReturnGameDriverSettings() { + assertThat(mDashboard.getPreferenceScreenResId()).isEqualTo(R.xml.game_driver_settings); + } +} diff --git a/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverEnableForAllAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverEnableForAllAppsPreferenceControllerTest.java new file mode 100644 index 00000000000..8f4c88ab7ce --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverEnableForAllAppsPreferenceControllerTest.java @@ -0,0 +1,117 @@ +/* + * 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.gamedriver; + +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_ALL_APPS; +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT; +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings; + +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +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 GameDriverEnableForAllAppsPreferenceControllerTest { + + @Mock + private PreferenceScreen mScreen; + @Mock + private SwitchPreference mPreference; + @Mock + private GameDriverContentObserver mGameDriverContentObserver; + + private Context mContext; + private ContentResolver mResolver; + private GameDriverEnableForAllAppsPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mResolver = mContext.getContentResolver(); + + Settings.Global.putInt(mResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1); + Settings.Global.putInt( + mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT); + + mController = new GameDriverEnableForAllAppsPreferenceController(mContext, "testKey"); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + mController.displayPreference(mScreen); + } + + @Test + public void displayPreference_shouldAddSwitchPreference() { + Settings.Global.putInt( + mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT); + mController.updateState(mPreference); + + verify(mPreference).setChecked(false); + } + + @Test + public void onStart_shouldRegister() { + mController.mGameDriverContentObserver = mGameDriverContentObserver; + mController.onStart(); + + verify(mGameDriverContentObserver).register(mResolver); + } + + @Test + public void onStop_shouldUnregister() { + mController.mGameDriverContentObserver = mGameDriverContentObserver; + mController.onStop(); + + verify(mGameDriverContentObserver).unregister(mResolver); + } + + @Test + public void onPreferenceChange_check_shouldUpdateSettingsGlobal() { + Settings.Global.putInt( + mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT); + mController.onPreferenceChange(mPreference, true); + + assertThat(Settings.Global.getInt( + mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT)) + .isEqualTo(GAME_DRIVER_ALL_APPS); + } + + @Test + public void onPreferenceChange_uncheck_shouldUpdateSettingsGlobal() { + Settings.Global.putInt( + mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_ALL_APPS); + mController.onPreferenceChange(mPreference, false); + + assertThat(Settings.Global.getInt( + mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT)) + .isEqualTo(GAME_DRIVER_DEFAULT); + } +} diff --git a/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverFooterPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverFooterPreferenceControllerTest.java new file mode 100644 index 00000000000..19676ed8b6a --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverFooterPreferenceControllerTest.java @@ -0,0 +1,123 @@ +/* + * 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.gamedriver; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_ALL_APPS; +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT; +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF; +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings; + +import androidx.preference.PreferenceScreen; + +import com.android.settingslib.widget.FooterPreference; + +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 GameDriverFooterPreferenceControllerTest { + + @Mock + private PreferenceScreen mScreen; + @Mock + private FooterPreference mPreference; + @Mock + private GameDriverContentObserver mGameDriverContentObserver; + + private Context mContext; + private ContentResolver mResolver; + private GameDriverFooterPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mResolver = mContext.getContentResolver(); + mController = spy(new GameDriverFooterPreferenceController(mContext)); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + } + + @Test + public void getAvailabilityStatus_gameDriverOff_availableUnsearchable() { + Settings.Global.putInt(mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + public void getAvailabilityStatus_gameDriverDefault_conditionallyUnavailable() { + Settings.Global.putInt( + mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void getAvailabilityStatus_gameDriverAllApps_conditionallyUnavailable() { + Settings.Global.putInt( + mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_ALL_APPS); + + assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void onStart_shouldRegister() { + mController.mGameDriverContentObserver = mGameDriverContentObserver; + mController.onStart(); + + verify(mGameDriverContentObserver).register(mResolver); + } + + @Test + public void onStop_shouldUnregister() { + mController.mGameDriverContentObserver = mGameDriverContentObserver; + mController.onStop(); + + verify(mGameDriverContentObserver).unregister(mResolver); + } + + @Test + public void updateState_available_visible() { + when(mController.getAvailabilityStatus()).thenReturn(AVAILABLE); + mController.updateState(mPreference); + + verify(mPreference).setVisible(true); + } + + @Test + public void updateState_unavailable_invisible() { + when(mController.getAvailabilityStatus()).thenReturn(CONDITIONALLY_UNAVAILABLE); + mController.updateState(mPreference); + + verify(mPreference).setVisible(false); + } +} diff --git a/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverGlobalSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverGlobalSwitchBarControllerTest.java new file mode 100644 index 00000000000..f0a302f2fb5 --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/gamedriver/GameDriverGlobalSwitchBarControllerTest.java @@ -0,0 +1,129 @@ +/* + * 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.gamedriver; + +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_DEFAULT; +import static com.android.settings.development.gamedriver.GameDriverEnableForAllAppsPreferenceController.GAME_DRIVER_OFF; +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.verify; + +import android.content.ContentResolver; +import android.content.Context; +import android.provider.Settings; + +import com.android.settings.widget.SwitchBar; +import com.android.settings.widget.SwitchBarController; +import com.android.settings.widget.SwitchWidgetController; + +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 GameDriverGlobalSwitchBarControllerTest { + + @Mock + private SwitchBar mSwitchBar; + @Mock + private SwitchWidgetController mSwitchWidgetController; + @Mock + private GameDriverContentObserver mGameDriverContentObserver; + + private Context mContext; + private ContentResolver mResolver; + private GameDriverGlobalSwitchBarController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mResolver = mContext.getContentResolver(); + } + + @Test + public void constructor_gameDriverOn_shouldCheckSwitchBar() { + Settings.Global.putInt( + mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT); + mController = new GameDriverGlobalSwitchBarController( + mContext, new SwitchBarController(mSwitchBar)); + + verify(mSwitchBar).setChecked(true); + } + + @Test + public void constructor_gameDriverOff_shouldUncheckSwitchBar() { + Settings.Global.putInt(mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF); + mController = new GameDriverGlobalSwitchBarController( + mContext, new SwitchBarController(mSwitchBar)); + + verify(mSwitchBar).setChecked(false); + } + + @Test + public void onStart_shouldStartListeningAndRegister() { + mController = new GameDriverGlobalSwitchBarController( + mContext, new SwitchBarController(mSwitchBar)); + mController.mSwitchWidgetController = mSwitchWidgetController; + mController.mGameDriverContentObserver = mGameDriverContentObserver; + mController.onStart(); + + verify(mSwitchWidgetController).startListening(); + verify(mGameDriverContentObserver).register(mResolver); + } + + @Test + public void onStop_shouldStopListeningAndUnregister() { + mController = new GameDriverGlobalSwitchBarController( + mContext, new SwitchBarController(mSwitchBar)); + mController.mSwitchWidgetController = mSwitchWidgetController; + mController.mGameDriverContentObserver = mGameDriverContentObserver; + mController.onStop(); + + verify(mSwitchWidgetController).stopListening(); + verify(mGameDriverContentObserver).unregister(mResolver); + } + + @Test + public void onSwitchToggled_checked_shouldTurnOnGameDriver() { + Settings.Global.putInt(mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_OFF); + mController = new GameDriverGlobalSwitchBarController( + mContext, new SwitchBarController(mSwitchBar)); + mController.onSwitchToggled(true); + + assertThat(Settings.Global.getInt( + mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT)) + .isEqualTo(GAME_DRIVER_DEFAULT); + } + + @Test + public void onSwitchToggled_unchecked_shouldTurnOffGameDriver() { + Settings.Global.putInt( + mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT); + mController = new GameDriverGlobalSwitchBarController( + mContext, new SwitchBarController(mSwitchBar)); + mController.onSwitchToggled(false); + + assertThat(Settings.Global.getInt( + mResolver, Settings.Global.GAME_DRIVER_ALL_APPS, GAME_DRIVER_DEFAULT)) + .isEqualTo(GAME_DRIVER_OFF); + } +}