From 2c5d1f8d293155ea9c4df78d2515e5ecdc2d8652 Mon Sep 17 00:00:00 2001 From: George Date: Mon, 2 Jan 2023 18:13:43 +0800 Subject: [PATCH] Adding Nfc Tag App Preference setting to special_access settings In the settings app, allow users to change the preference of the Nfc Tag apps. Bug: 244272155 Test: make RunSettingsRoboTests ROBOTEST_FILTER=NfcTagAppsPreferenceControllerTest Change-Id: I28903fae8935613a0e8618da21ca44e98b8801d5 --- res/values/strings.xml | 12 ++ res/xml/change_nfc_tag_apps_details.xml | 30 ++++ res/xml/special_access.xml | 11 ++ src/com/android/settings/Settings.java | 2 + .../manageapplications/AppFilterRegistry.java | 16 ++- .../ManageApplications.java | 28 +++- .../ManageApplicationsUtil.kt | 3 + .../nfc/AppStateNfcTagAppsBridge.java | 136 ++++++++++++++++++ .../nfc/ChangeNfcTagAppsStateDetails.java | 118 +++++++++++++++ .../nfc/NfcTagAppsPreferenceController.java | 42 ++++++ .../NfcTagAppsPreferenceControllerTest.java | 66 +++++++++ .../testutils/shadow/ShadowNfcAdapter.java | 12 +- 12 files changed, 469 insertions(+), 7 deletions(-) create mode 100644 res/xml/change_nfc_tag_apps_details.xml create mode 100644 src/com/android/settings/nfc/AppStateNfcTagAppsBridge.java create mode 100644 src/com/android/settings/nfc/ChangeNfcTagAppsStateDetails.java create mode 100644 src/com/android/settings/nfc/NfcTagAppsPreferenceController.java create mode 100644 tests/robotests/src/com/android/settings/nfc/NfcTagAppsPreferenceControllerTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index f12824780df..b35e3960f4b 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -6916,6 +6916,9 @@ always on display, AOD + + nfc, tag, reader + Volume, vibration, Do Not Disturb @@ -10238,6 +10241,15 @@ Allow this app to turn Wi-Fi on or off, scan and connect to Wi-Fi networks, add or remove networks, or start a local-only hotspot + + NFC Tag apps control + + + Allow app to popup upon NFC tags detected + + + Allow this app to launch and get tag contents when the device detests NFC tags + Play media to diff --git a/res/xml/change_nfc_tag_apps_details.xml b/res/xml/change_nfc_tag_apps_details.xml new file mode 100644 index 00000000000..74ccfde4f54 --- /dev/null +++ b/res/xml/change_nfc_tag_apps_details.xml @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/res/xml/special_access.xml b/res/xml/special_access.xml index 1b4aeb0ada4..c10d5cc13f0 100644 --- a/res/xml/special_access.xml +++ b/res/xml/special_access.xml @@ -197,4 +197,15 @@ android:title="@string/special_access_more" android:order="-100" settings:controller="com.android.settings.applications.specialaccess.MoreSpecialAccessPreferenceController" /> + + + + diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java index f9671b0e4af..f037a05ac14 100644 --- a/src/com/android/settings/Settings.java +++ b/src/com/android/settings/Settings.java @@ -348,6 +348,8 @@ public class Settings extends SettingsActivity { public static class AppMediaManagementAppsActivity extends SettingsActivity { /* empty */ } public static class WriteSettingsActivity extends SettingsActivity { /* empty */ } public static class ChangeWifiStateActivity extends SettingsActivity { /* empty */ } + /** Activity to manage NFC Tag applications. */ + public static class ChangeNfcTagAppsActivity extends SettingsActivity { /* empty */ } public static class AppDrawOverlaySettingsActivity extends SettingsActivity { /* empty */ } public static class AppWriteSettingsActivity extends SettingsActivity { /* empty */ } /** Activity to manage app battery usage details. */ diff --git a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java index 1e6ecd83d5a..f3195921dcb 100644 --- a/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java +++ b/src/com/android/settings/applications/manageapplications/AppFilterRegistry.java @@ -32,6 +32,7 @@ import com.android.settings.applications.AppStateOverlayBridge; import com.android.settings.applications.AppStatePowerBridge; import com.android.settings.applications.AppStateUsageBridge; import com.android.settings.applications.AppStateWriteSettingsBridge; +import com.android.settings.nfc.AppStateNfcTagAppsBridge; import com.android.settings.wifi.AppStateChangeWifiStateBridge; import com.android.settingslib.applications.ApplicationsState; @@ -65,6 +66,7 @@ public class AppFilterRegistry { FILTER_APPS_BATTERY_RESTRICTED, FILTER_LONG_BACKGROUND_TASKS, FILTER_APPS_CLONE, + FILTER_APPS_NFC_TAG, }) @interface FilterType {} @@ -95,8 +97,9 @@ public class AppFilterRegistry { public static final int FILTER_APPS_BATTERY_RESTRICTED = 23; public static final int FILTER_LONG_BACKGROUND_TASKS = 24; public static final int FILTER_APPS_CLONE = 25; - // Next id: 26. If you add an entry here, please change NUM_FILTER_ENTRIES. - private static final int NUM_FILTER_ENTRIES = 26; + public static final int FILTER_APPS_NFC_TAG = 26; + private static final int NUM_FILTER_ENTRIES = 27; + // Next id: 27. If you add an entry here, please change NUM_FILTER_ENTRIES. private static AppFilterRegistry sRegistry; @@ -261,6 +264,13 @@ public class AppFilterRegistry { AppStateClonedAppsBridge.FILTER_APPS_CLONE, FILTER_APPS_CLONE, R.string.cloned_apps_dashboard_title); + + // Apps that are nfc tag allowlisted. + mFilters[FILTER_APPS_NFC_TAG] = + new AppFilterItem( + AppStateNfcTagAppsBridge.FILTER_APPS_NFC_TAG, + FILTER_APPS_NFC_TAG, + R.string.change_nfc_tag_apps_title); } public static AppFilterRegistry getInstance() { @@ -301,6 +311,8 @@ public class AppFilterRegistry { return FILTER_LONG_BACKGROUND_TASKS; case ManageApplications.LIST_TYPE_CLONED_APPS: return FILTER_APPS_CLONE; + case ManageApplications.LIST_TYPE_NFC_TAG_APPS: + return FILTER_APPS_NFC_TAG; default: return FILTER_APPS_ALL; } diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java index 44fbd83d054..7a60494bba8 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -99,6 +99,7 @@ import com.android.internal.jank.InteractionJankMonitor; import com.android.settings.R; import com.android.settings.Settings.AlarmsAndRemindersActivity; import com.android.settings.Settings.AppBatteryUsageActivity; +import com.android.settings.Settings.ChangeNfcTagAppsActivity; import com.android.settings.Settings.ChangeWifiStateActivity; import com.android.settings.Settings.ClonedAppsListActivity; import com.android.settings.Settings.HighPowerApplicationsActivity; @@ -148,6 +149,8 @@ import com.android.settings.dashboard.profileselector.ProfileSelectFragment; import com.android.settings.fuelgauge.AdvancedPowerUsageDetail; import com.android.settings.fuelgauge.HighPowerDetail; import com.android.settings.localepicker.AppLocalePickerActivity; +import com.android.settings.nfc.AppStateNfcTagAppsBridge; +import com.android.settings.nfc.ChangeNfcTagAppsStateDetails; import com.android.settings.notification.ConfigureNotificationSettings; import com.android.settings.notification.NotificationBackend; import com.android.settings.notification.app.AppNotificationSettings; @@ -264,6 +267,7 @@ public class ManageApplications extends InstrumentedFragment public static final int LIST_TYPE_BATTERY_OPTIMIZATION = 15; public static final int LIST_TYPE_LONG_BACKGROUND_TASKS = 16; public static final int LIST_TYPE_CLONED_APPS = 17; + public static final int LIST_TYPE_NFC_TAG_APPS = 18; // List types that should show instant apps. public static final Set LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList( @@ -362,6 +366,9 @@ public class ManageApplications extends InstrumentedFragment 1); // USER_INTERACTED } break; + case LIST_TYPE_NFC_TAG_APPS: + mShowSystem = true; + break; } final AppFilterRegistry appFilterRegistry = AppFilterRegistry.getInstance(); mFilter = appFilterRegistry.get(appFilterRegistry.getDefaultFilterType(mListType)); @@ -560,6 +567,8 @@ public class ManageApplications extends InstrumentedFragment return SettingsEnums.LONG_BACKGROUND_TASKS; case LIST_TYPE_CLONED_APPS: return SettingsEnums.CLONED_APPS; + case LIST_TYPE_NFC_TAG_APPS: + return SettingsEnums.CONFIG_NFC_TAG_APP_PREF; default: return SettingsEnums.PAGE_UNKNOWN; } @@ -629,10 +638,9 @@ public class ManageApplications extends InstrumentedFragment @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == INSTALLED_APP_DETAILS && mCurrentPkgName != null) { - if (mListType == LIST_TYPE_NOTIFICATION) { - mApplications.mExtraInfoBridge.forceUpdate(mCurrentPkgName, mCurrentUid); - } else if (mListType == LIST_TYPE_HIGH_POWER || mListType == LIST_TYPE_OVERLAY - || mListType == LIST_TYPE_WRITE_SETTINGS) { + if (mListType == LIST_TYPE_NOTIFICATION || mListType == LIST_TYPE_HIGH_POWER + || mListType == LIST_TYPE_OVERLAY || mListType == LIST_TYPE_WRITE_SETTINGS + || mListType == LIST_TYPE_NFC_TAG_APPS) { mApplications.mExtraInfoBridge.forceUpdate(mCurrentPkgName, mCurrentUid); } else { mApplicationsState.requestSize(mCurrentPkgName, UserHandle.getUserId(mCurrentUid)); @@ -727,6 +735,10 @@ public class ManageApplications extends InstrumentedFragment .getRoute(mCurrentPkgName, userId)); } break; + case LIST_TYPE_NFC_TAG_APPS: + startAppInfoFragment(ChangeNfcTagAppsStateDetails.class, + R.string.change_nfc_tag_apps_title); + break; // TODO: Figure out if there is a way where we can spin up the profile's settings // process ahead of time, to avoid a long load of data when user clicks on a managed // app. Maybe when they load the list of apps that contains managed profile apps. @@ -1052,6 +1064,8 @@ public class ManageApplications extends InstrumentedFragment screenTitle = R.string.long_background_tasks_title; } else if (className.equals(ClonedAppsListActivity.class.getName())) { screenTitle = R.string.cloned_apps_dashboard_title; + } else if (className.equals(ChangeNfcTagAppsActivity.class.getName())) { + screenTitle = R.string.change_nfc_tag_apps_title; } else { if (screenTitle == -1) { screenTitle = R.string.all_apps; @@ -1260,6 +1274,8 @@ public class ManageApplications extends InstrumentedFragment mExtraInfoBridge = new AppStateLongBackgroundTasksBridge(mContext, mState, this); } else if (mManageApplications.mListType == LIST_TYPE_CLONED_APPS) { mExtraInfoBridge = new AppStateClonedAppsBridge(mContext, mState, this); + } else if (mManageApplications.mListType == LIST_TYPE_NFC_TAG_APPS) { + mExtraInfoBridge = new AppStateNfcTagAppsBridge(mContext, mState, this); } else { mExtraInfoBridge = null; } @@ -1810,6 +1826,10 @@ public class ManageApplications extends InstrumentedFragment case LIST_TYPE_CLONED_APPS: holder.setSummary(null); break; + case LIST_TYPE_NFC_TAG_APPS: + holder.setSummary( + ChangeNfcTagAppsStateDetails.getSummary(mContext, entry)); + break; default: holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize); break; diff --git a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt index 8c4c41dfd05..6be5c207f28 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt +++ b/src/com/android/settings/applications/manageapplications/ManageApplicationsUtil.kt @@ -20,6 +20,7 @@ import android.content.Context import android.util.FeatureFlagUtils import com.android.settings.Settings.AlarmsAndRemindersActivity import com.android.settings.Settings.AppBatteryUsageActivity +import com.android.settings.Settings.ChangeNfcTagAppsActivity import com.android.settings.Settings.ChangeWifiStateActivity import com.android.settings.Settings.ClonedAppsListActivity import com.android.settings.Settings.GamesStorageActivity @@ -46,6 +47,7 @@ import com.android.settings.applications.manageapplications.ManageApplications.L import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MAIN import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MANAGE_SOURCES import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_MEDIA_MANAGEMENT_APPS +import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_NFC_TAG_APPS import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_NOTIFICATION import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_OVERLAY import com.android.settings.applications.manageapplications.ManageApplications.LIST_TYPE_STORAGE @@ -85,6 +87,7 @@ object ManageApplicationsUtil { AppBatteryUsageActivity::class to LIST_TYPE_BATTERY_OPTIMIZATION, LongBackgroundTasksActivity::class to LIST_TYPE_LONG_BACKGROUND_TASKS, ClonedAppsListActivity::class to LIST_TYPE_CLONED_APPS, + ChangeNfcTagAppsActivity::class to LIST_TYPE_NFC_TAG_APPS, ) @JvmField diff --git a/src/com/android/settings/nfc/AppStateNfcTagAppsBridge.java b/src/com/android/settings/nfc/AppStateNfcTagAppsBridge.java new file mode 100644 index 00000000000..0d705d5c9ac --- /dev/null +++ b/src/com/android/settings/nfc/AppStateNfcTagAppsBridge.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2023 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.nfc; + +import static com.android.settingslib.applications.ApplicationsState.AppEntry; +import static com.android.settingslib.applications.ApplicationsState.AppFilter; + +import android.app.ActivityManager; +import android.content.Context; +import android.nfc.NfcAdapter; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; + +import com.android.settings.applications.AppStateBaseBridge; +import com.android.settingslib.applications.ApplicationsState; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Filter to display only in the Tag preference listed Apps on Nfc Tag Apps page. + */ +public class AppStateNfcTagAppsBridge extends AppStateBaseBridge{ + + private static final String TAG = "AppStateNfcTagAppsBridge"; + + private final Context mContext; + private final NfcAdapter mNfcAdapter; + // preference list cache + private static Map> sList = new HashMap<>(); + + public AppStateNfcTagAppsBridge(Context context, ApplicationsState appState, + Callback callback) { + super(appState, callback); + mContext = context; + mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext); + if (mNfcAdapter != null && mNfcAdapter.isTagIntentAppPreferenceSupported()) { + UserManager um = mContext.createContextAsUser( + UserHandle.of(ActivityManager.getCurrentUser()), 0) + .getSystemService(UserManager.class); + List luh = um.getEnabledProfiles(); + for (UserHandle uh : luh) { + int userId = uh.getIdentifier(); + sList.put(userId, mNfcAdapter.getTagIntentAppPreferenceForUser(userId)); + } + } + } + + /** + * Update the system and cached tag app preference lists. + */ + public boolean updateApplist(int userId, String pkg, boolean allowed) { + if (mNfcAdapter.setTagIntentAppPreferenceForUser( + userId, pkg, allowed) == NfcAdapter.TAG_INTENT_APP_PREF_RESULT_SUCCESS) { + sList.put(userId, mNfcAdapter.getTagIntentAppPreferenceForUser(userId)); + return true; + } else { + return false; + } + } + + @Override + protected void loadAllExtraInfo() { + final List allApps = mAppSession.getAllApps(); + for (int i = 0; i < allApps.size(); i++) { + ApplicationsState.AppEntry app = allApps.get(i); + this.updateExtraInfo(app, app.info.packageName, app.info.uid); + } + } + + @Override + protected void updateExtraInfo(AppEntry app, String pkg, int uid) { + // Display package if is in the app preference list. + int userId = UserHandle.getUserId(uid); + Map map = sList.getOrDefault(userId, new HashMap<>()); + if (map.containsKey(pkg)) { + app.extraInfo = new NfcTagAppState(/* exist */ true, /* allowed */ map.get(pkg)); + } else { + app.extraInfo = new NfcTagAppState(/* exist */ false, /* allowed */ false); + } + } + + /** + * Class to denote the nfc tag app preference state of the AppEntry + */ + public static class NfcTagAppState { + private boolean mIsExisted; + private boolean mIsAllowed; + + public NfcTagAppState(boolean exist, boolean allowed) { + mIsExisted = exist; + mIsAllowed = allowed; + } + + public boolean isExisted() { + return mIsExisted; + } + + public boolean isAllowed() { + return mIsAllowed; + } + } + + public static final AppFilter FILTER_APPS_NFC_TAG = + new AppFilter() { + @Override + public void init() { + } + + @Override + public boolean filterApp(AppEntry entry) { + if (entry.extraInfo == null) { + Log.d(TAG, "[" + entry.info.packageName + "]" + " has No extra info."); + return false; + } + NfcTagAppState state = (NfcTagAppState) entry.extraInfo; + return state.isExisted(); + } + }; +} diff --git a/src/com/android/settings/nfc/ChangeNfcTagAppsStateDetails.java b/src/com/android/settings/nfc/ChangeNfcTagAppsStateDetails.java new file mode 100644 index 00000000000..99c23cd98ad --- /dev/null +++ b/src/com/android/settings/nfc/ChangeNfcTagAppsStateDetails.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2023 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.nfc; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.os.Bundle; +import android.util.Log; + +import androidx.appcompat.app.AlertDialog; +import androidx.preference.Preference; +import androidx.preference.Preference.OnPreferenceChangeListener; +import androidx.preference.SwitchPreference; + +import com.android.settings.R; +import com.android.settings.applications.AppInfoWithHeader; +import com.android.settings.nfc.AppStateNfcTagAppsBridge.NfcTagAppState; +import com.android.settingslib.applications.ApplicationsState.AppEntry; + +/** + * Class for displaying app info of the Nfc Tag App + */ +public class ChangeNfcTagAppsStateDetails extends AppInfoWithHeader + implements OnPreferenceChangeListener { + + private static final String KEY_APP_OPS_SETTINGS_SWITCH = "app_ops_settings_switch"; + private static final String LOG_TAG = "ChangeNfcTagAppsStateDetails"; + + private AppStateNfcTagAppsBridge mAppBridge; + private SwitchPreference mSwitchPref; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + final Context context = getActivity(); + mAppBridge = new AppStateNfcTagAppsBridge(context, mState, null); + + // find preferences + addPreferencesFromResource(R.xml.change_nfc_tag_apps_details); + mSwitchPref = (SwitchPreference) findPreference(KEY_APP_OPS_SETTINGS_SWITCH); + + // set title/summary for all of them + mSwitchPref.setTitle(R.string.change_nfc_tag_apps_detail_switch); + + // install event listeners + mSwitchPref.setOnPreferenceChangeListener(this); + + } + + @Override + protected AlertDialog createDialog(int id, int errorCode) { + return null; + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.CONFIG_NFC_TAG_APP_PREF; + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + Boolean enable = (Boolean) newValue; + if (preference == mSwitchPref) { + if (mAppBridge != null && mAppBridge.updateApplist(mUserId, mPackageName, enable)) { + refreshUi(); + return true; + } else { + Log.e(LOG_TAG, "Set [" + mPackageName + "]" + " failed."); + return false; + } + } + return false; + } + + @Override + protected boolean refreshUi() { + if (mPackageInfo == null || mPackageInfo.applicationInfo == null) { + return false; + } + retrieveAppEntry(); + NfcTagAppState state; + if (mAppEntry.extraInfo instanceof NfcTagAppState) { + state = (NfcTagAppState) mAppEntry.extraInfo; + } else { + state = new NfcTagAppState(/* exist */ false, /* allowed */ false); + } + mSwitchPref.setChecked(state.isAllowed()); + mSwitchPref.setEnabled(state.isExisted()); + return true; + } + + /** Returns the summary string for this setting preference. */ + public static CharSequence getSummary(Context context, AppEntry entry) { + NfcTagAppState state; + if (entry.extraInfo instanceof NfcTagAppState) { + state = (NfcTagAppState) entry.extraInfo; + } else { + state = new NfcTagAppState(/* exist */ false, /* allowed */ false); + } + return context.getString(state.isAllowed() + ? R.string.app_permission_summary_allowed + : R.string.app_permission_summary_not_allowed); + } +} diff --git a/src/com/android/settings/nfc/NfcTagAppsPreferenceController.java b/src/com/android/settings/nfc/NfcTagAppsPreferenceController.java new file mode 100644 index 00000000000..36de84d301e --- /dev/null +++ b/src/com/android/settings/nfc/NfcTagAppsPreferenceController.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2023 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.nfc; + +import android.content.Context; +import android.nfc.NfcAdapter; + +import com.android.settings.core.BasePreferenceController; + +/** + * A PreferenceController handling the logic for the Nfc Tag App preference + */ +public class NfcTagAppsPreferenceController extends BasePreferenceController { + private NfcAdapter mNfcAdapter; + + public NfcTagAppsPreferenceController(Context context, String preferenceKey) { + super(context, preferenceKey); + mNfcAdapter = NfcAdapter.getDefaultAdapter(context.getApplicationContext()); + } + + @Override + public int getAvailabilityStatus() { + if (mNfcAdapter != null) { + return mNfcAdapter.isTagIntentAppPreferenceSupported() + ? AVAILABLE : UNSUPPORTED_ON_DEVICE; + } + return UNSUPPORTED_ON_DEVICE; + } +} diff --git a/tests/robotests/src/com/android/settings/nfc/NfcTagAppsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/NfcTagAppsPreferenceControllerTest.java new file mode 100644 index 00000000000..7e42c2c30a7 --- /dev/null +++ b/tests/robotests/src/com/android/settings/nfc/NfcTagAppsPreferenceControllerTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2023 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.nfc; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; + +import android.content.Context; +import android.nfc.NfcAdapter; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.testutils.shadow.ShadowNfcAdapter; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = ShadowNfcAdapter.class) +public class NfcTagAppsPreferenceControllerTest { + + private NfcTagAppsPreferenceController mController; + private static final String KEY = "key"; + private ShadowNfcAdapter mShadowNfcAdapter; + private Context mContext; + + @Before + public void setUp() { + mContext = spy(ApplicationProvider.getApplicationContext()); + mController = new NfcTagAppsPreferenceController(mContext, KEY); + mShadowNfcAdapter = Shadow.extract(NfcAdapter.getDefaultAdapter(mContext)); + } + + @Test + public void getAvailabilityStatus_featureNotEnabled_shouldNotReturnAvailable() { + mShadowNfcAdapter.setTagIntentAppPreferenceSupported(false); + assertThat(mController.getAvailabilityStatus()).isNotEqualTo(AVAILABLE); + } + + @Test + public void getAvailabilityStatus_featureEnabled_shouldReturnAvailable() { + mShadowNfcAdapter.setTagIntentAppPreferenceSupported(true); + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } +} diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowNfcAdapter.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowNfcAdapter.java index 54f665c75d9..46c968f1675 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowNfcAdapter.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowNfcAdapter.java @@ -38,6 +38,7 @@ public class ShadowNfcAdapter extends org.robolectric.shadows.ShadowNfcAdapter { private boolean mIsNfcEnabled = false; private int mState = NfcAdapter.STATE_ON; private boolean mIsSecureNfcSupported = false; + private boolean mIsTagIntentAppPreferenceSupported = false; @Implementation protected void enableReaderMode(Activity activity, NfcAdapter.ReaderCallback callback, @@ -97,4 +98,13 @@ public class ShadowNfcAdapter extends org.robolectric.shadows.ShadowNfcAdapter { public static void reset() { sReaderModeEnabled = false; } -} \ No newline at end of file + + public void setTagIntentAppPreferenceSupported(boolean supported) { + mIsTagIntentAppPreferenceSupported = supported; + } + + @Implementation + protected boolean isTagIntentAppPreferenceSupported() { + return mIsTagIntentAppPreferenceSupported; + } +}