diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 42f11a0a192..4c33c058faa 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1763,6 +1763,7 @@ android:resource="@string/suggested_fingerprint_lock_settings_title" /> + diff --git a/res/drawable/ic_find_device_enabled.xml b/res/drawable/ic_find_device_enabled.xml index 16f0245c8f6..614ac6d136a 100644 --- a/res/drawable/ic_find_device_enabled.xml +++ b/res/drawable/ic_find_device_enabled.xml @@ -20,6 +20,6 @@ android:viewportHeight="24"> diff --git a/res/drawable/ic_ota_update_available.xml b/res/drawable/ic_ota_update_available.xml index 2b0d82dc786..b03f9d741aa 100644 --- a/res/drawable/ic_ota_update_available.xml +++ b/res/drawable/ic_ota_update_available.xml @@ -20,6 +20,6 @@ android:viewportHeight="24"> diff --git a/res/drawable/ic_ota_update_current.xml b/res/drawable/ic_ota_update_current.xml index e9b987a2c48..c38a0838d57 100644 --- a/res/drawable/ic_ota_update_current.xml +++ b/res/drawable/ic_ota_update_current.xml @@ -20,6 +20,6 @@ android:viewportHeight="24"> diff --git a/res/drawable/ic_ota_update_none.xml b/res/drawable/ic_ota_update_none.xml index a01a459c164..b49b4247646 100644 --- a/res/drawable/ic_ota_update_none.xml +++ b/res/drawable/ic_ota_update_none.xml @@ -14,19 +14,12 @@ limitations under the License. --> + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + - + android:fillColor="#FFF44336" + android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7zM11,15h2v2h-2V15zM13,8h-2v5h2V8z"/> diff --git a/res/drawable/ic_ota_update_stale.xml b/res/drawable/ic_ota_update_stale.xml index 266920bbbe4..b49b4247646 100644 --- a/res/drawable/ic_ota_update_stale.xml +++ b/res/drawable/ic_ota_update_stale.xml @@ -20,6 +20,6 @@ android:viewportHeight="24"> diff --git a/res/drawable/ic_package_verifier_disabled.xml b/res/drawable/ic_package_verifier_disabled.xml index 9dfcb9d8193..49fe0d33ae6 100644 --- a/res/drawable/ic_package_verifier_disabled.xml +++ b/res/drawable/ic_package_verifier_disabled.xml @@ -20,6 +20,6 @@ android:viewportHeight="24"> diff --git a/res/drawable/ic_package_verifier_enabled.xml b/res/drawable/ic_package_verifier_enabled.xml index 670ede4d174..1e09eee9b15 100644 --- a/res/drawable/ic_package_verifier_enabled.xml +++ b/res/drawable/ic_package_verifier_enabled.xml @@ -20,6 +20,6 @@ android:viewportHeight="24"> diff --git a/res/drawable/ic_package_verifier_removed.xml b/res/drawable/ic_package_verifier_removed.xml index 66ad8ed385e..d3680e70924 100644 --- a/res/drawable/ic_package_verifier_removed.xml +++ b/res/drawable/ic_package_verifier_removed.xml @@ -19,6 +19,6 @@ android:viewportWidth="24" android:viewportHeight="24"> diff --git a/res/layout/condition_container.xml b/res/layout/condition_container.xml index a917ad94652..877b17a4413 100644 --- a/res/layout/condition_container.xml +++ b/res/layout/condition_container.xml @@ -22,8 +22,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="16dp" - android:paddingStart="16dp" - android:paddingEnd="16dp" + android:paddingStart="14dp" + android:paddingEnd="14dp" android:paddingBottom="@dimen/dashboard_padding_bottom"> + + + + + diff --git a/res/xml/sound_settings.xml b/res/xml/sound_settings.xml index c0798079db8..15fbcc84d41 100644 --- a/res/xml/sound_settings.xml +++ b/res/xml/sound_settings.xml @@ -141,6 +141,11 @@ android:key="screen_locking_sounds" android:title="@string/screen_locking_sounds_title" /> + + + { String packageName = null; if (tile.intent != null) { @@ -259,11 +262,11 @@ public class DashboardFeatureProviderImpl implements DashboardFeatureProvider { return; } final Icon icon = Icon.createWithResource(iconInfo.first, iconInfo.second); - ThreadUtils.postOnMainThread(() -> { - preference.setIcon(icon.loadDrawable(preference.getContext())); - } + ThreadUtils.postOnMainThread(() -> + preference.setIcon(icon.loadDrawable(preference.getContext())) ); }); + } } private void launchIntentOrSelectProfile(Activity activity, Tile tile, Intent intent, diff --git a/src/com/android/settings/development/qstile/DevelopmentTiles.java b/src/com/android/settings/development/qstile/DevelopmentTiles.java index 1094ab9c7bb..5482b028d35 100644 --- a/src/com/android/settings/development/qstile/DevelopmentTiles.java +++ b/src/com/android/settings/development/qstile/DevelopmentTiles.java @@ -34,6 +34,7 @@ import android.view.WindowManagerGlobal; import android.widget.Toast; import com.android.internal.app.LocalePicker; +import com.android.settingslib.development.DevelopmentSettingsEnabler; import com.android.settingslib.development.SystemPropPoker; public abstract class DevelopmentTiles extends TileService { @@ -50,7 +51,18 @@ public abstract class DevelopmentTiles extends TileService { } public void refresh() { - getQsTile().setState(isEnabled() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE); + final int state; + if (!DevelopmentSettingsEnabler.isDevelopmentSettingsEnabled(this)) { + // Reset to disabled state if dev option is off. + if (isEnabled()) { + setIsEnabled(false); + SystemPropPoker.getInstance().poke(); + } + state = Tile.STATE_UNAVAILABLE; + } else { + state = isEnabled() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE; + } + getQsTile().setState(state); getQsTile().updateTile(); } @@ -124,7 +136,8 @@ public abstract class DevelopmentTiles extends TileService { IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); try { return wm.getAnimationScale(0) != 1; - } catch (RemoteException e) { } + } catch (RemoteException e) { + } return false; } @@ -136,7 +149,8 @@ public abstract class DevelopmentTiles extends TileService { wm.setAnimationScale(0, scale); wm.setAnimationScale(1, scale); wm.setAnimationScale(2, scale); - } catch (RemoteException e) { } + } catch (RemoteException e) { + } } } diff --git a/src/com/android/settings/nfc/BaseNfcPreferenceController.java b/src/com/android/settings/nfc/BaseNfcPreferenceController.java index f9cd88a9651..e8e7dfd4843 100644 --- a/src/com/android/settings/nfc/BaseNfcPreferenceController.java +++ b/src/com/android/settings/nfc/BaseNfcPreferenceController.java @@ -19,11 +19,8 @@ import android.content.Context; import android.database.ContentObserver; import android.net.Uri; import android.nfc.NfcAdapter; -import android.nfc.NfcManager; import android.os.Handler; import android.provider.Settings; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; import com.android.settings.core.PreferenceControllerMixin; import com.android.settingslib.core.AbstractPreferenceController; @@ -31,7 +28,8 @@ import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnPause; import com.android.settingslib.core.lifecycle.events.OnResume; -import java.util.List; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; public abstract class BaseNfcPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause { @@ -65,13 +63,6 @@ public abstract class BaseNfcPreferenceController extends AbstractPreferenceCont } } - @Override - public void updateNonIndexableKeys(List keys) { - if (!isAvailable()) { - keys.add(getPreferenceKey()); - } - } - @Override public boolean isAvailable() { return mNfcAdapter != null; diff --git a/src/com/android/settings/nfc/NfcForegroundPreference.java b/src/com/android/settings/nfc/NfcForegroundPreference.java deleted file mode 100644 index 728f2e4b598..00000000000 --- a/src/com/android/settings/nfc/NfcForegroundPreference.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2015 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 androidx.preference.DropDownPreference; -import androidx.preference.Preference; - -import com.android.settings.R; - -public class NfcForegroundPreference extends DropDownPreference implements - PaymentBackend.Callback, Preference.OnPreferenceChangeListener { - - private final PaymentBackend mPaymentBackend; - public NfcForegroundPreference(Context context, PaymentBackend backend) { - super(context); - mPaymentBackend = backend; - mPaymentBackend.registerCallback(this); - - setTitle(getContext().getString(R.string.nfc_payment_use_default)); - setEntries(new CharSequence[] { - getContext().getString(R.string.nfc_payment_favor_open), - getContext().getString(R.string.nfc_payment_favor_default) - }); - setEntryValues(new CharSequence[] { "1", "0" }); - refresh(); - setOnPreferenceChangeListener(this); - } - - @Override - public void onPaymentAppsChanged() { - refresh(); - } - - void refresh() { - boolean foregroundMode = mPaymentBackend.isForegroundMode(); - if (foregroundMode) { - setValue("1"); - } else { - setValue("0"); - } - setSummary(getEntry()); - } - - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - String newValueString = (String) newValue; - setSummary(getEntries()[findIndexOfValue(newValueString)]); - mPaymentBackend.setForegroundMode(Integer.parseInt(newValueString) != 0); - return true; - } -} diff --git a/src/com/android/settings/nfc/NfcForegroundPreferenceController.java b/src/com/android/settings/nfc/NfcForegroundPreferenceController.java new file mode 100644 index 00000000000..fbc5a32feda --- /dev/null +++ b/src/com/android/settings/nfc/NfcForegroundPreferenceController.java @@ -0,0 +1,129 @@ +/* + * Copyright (C) 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.nfc; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.text.TextUtils; + +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 java.util.List; + +import androidx.preference.DropDownPreference; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +public class NfcForegroundPreferenceController extends BasePreferenceController implements + PaymentBackend.Callback, Preference.OnPreferenceChangeListener, + LifecycleObserver, OnStart, OnStop { + + private DropDownPreference mPreference; + private PaymentBackend mPaymentBackend; + + public NfcForegroundPreferenceController(Context context, String key) { + super(context, key); + } + + public void setPaymentBackend(PaymentBackend backend) { + mPaymentBackend = backend; + } + + @Override + public void onStart() { + if (mPaymentBackend != null) { + mPaymentBackend.registerCallback(this); + } + } + + @Override + public void onStop() { + if (mPaymentBackend != null) { + mPaymentBackend.unregisterCallback(this); + } + } + + @Override + public int getAvailabilityStatus() { + final PackageManager pm = mContext.getPackageManager(); + if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC)) { + return DISABLED_UNSUPPORTED; + } + if (mPaymentBackend == null) { + return DISABLED_UNSUPPORTED; + } + final List appInfos = mPaymentBackend.getPaymentAppInfos(); + return (appInfos != null && !appInfos.isEmpty()) + ? AVAILABLE + : DISABLED_UNSUPPORTED; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = (DropDownPreference) screen.findPreference(getPreferenceKey()); + if (mPreference == null) { + return; + } + + mPreference.setEntries(new CharSequence[] { + mContext.getText(R.string.nfc_payment_favor_open), + mContext.getText(R.string.nfc_payment_favor_default) + }); + mPreference.setEntryValues(new CharSequence[] {"1", "0"}); + } + + @Override + public void onPaymentAppsChanged() { + updateState(mPreference); + } + + @Override + public void updateState(Preference preference) { + if (preference instanceof DropDownPreference) { + ((DropDownPreference) preference).setValue( + mPaymentBackend.isForegroundMode() ? "1" : "0"); + } + super.updateState(preference); + } + + @Override + public CharSequence getSummary() { + return mPreference.getEntry(); + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + if (!(preference instanceof DropDownPreference)) { + return false; + } + final DropDownPreference pref = (DropDownPreference) preference; + final String newValueString = (String) newValue; + pref.setSummary(pref.getEntries()[pref.findIndexOfValue(newValueString)]); + mPaymentBackend.setForegroundMode(Integer.parseInt(newValueString) != 0); + return true; + } + + @Override + public void updateNonIndexableKeys(List keys) { + final String key = getPreferenceKey(); + if (!TextUtils.isEmpty(key)) { + keys.add(key); + } + } +} \ No newline at end of file diff --git a/src/com/android/settings/nfc/NfcPaymentPreference.java b/src/com/android/settings/nfc/NfcPaymentPreference.java index 0838a90e622..456115ad670 100644 --- a/src/com/android/settings/nfc/NfcPaymentPreference.java +++ b/src/com/android/settings/nfc/NfcPaymentPreference.java @@ -16,80 +16,49 @@ package com.android.settings.nfc; import android.app.AlertDialog; -import android.content.ActivityNotFoundException; import android.content.Context; -import android.app.Dialog; import android.content.DialogInterface; -import android.content.Intent; -import androidx.preference.PreferenceViewHolder; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.CompoundButton; -import android.widget.ImageView; -import android.widget.RadioButton; +import android.util.AttributeSet; -import com.android.settings.R; -import com.android.settings.nfc.PaymentBackend.PaymentAppInfo; import com.android.settingslib.CustomDialogPreference; -import java.util.List; +import androidx.preference.PreferenceViewHolder; -public class NfcPaymentPreference extends CustomDialogPreference implements - PaymentBackend.Callback, View.OnClickListener { +public class NfcPaymentPreference extends CustomDialogPreference { - private static final String TAG = "NfcPaymentPreference"; + private Listener mListener; - private final NfcPaymentAdapter mAdapter; - private final Context mContext; - private final LayoutInflater mLayoutInflater; - private final PaymentBackend mPaymentBackend; + interface Listener { + void onBindViewHolder(PreferenceViewHolder view); - // Fields below only modified on UI thread - private ImageView mSettingsButtonView; + void onPrepareDialogBuilder(AlertDialog.Builder builder, + DialogInterface.OnClickListener listener); + } - public NfcPaymentPreference(Context context, PaymentBackend backend) { - super(context, null); - mPaymentBackend = backend; - mContext = context; - backend.registerCallback(this); - mAdapter = new NfcPaymentAdapter(); - setDialogTitle(context.getString(R.string.nfc_payment_pay_with)); - mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - setWidgetLayoutResource(R.layout.preference_widget_gear); + public NfcPaymentPreference(Context context, AttributeSet attrs, int defStyleAttr, + int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + } - refresh(); + public NfcPaymentPreference(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + public NfcPaymentPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + void initialize(Listener listener) { + mListener = listener; } @Override public void onBindViewHolder(PreferenceViewHolder view) { super.onBindViewHolder(view); - mSettingsButtonView = (ImageView) view.findViewById(R.id.settings_button); - mSettingsButtonView.setOnClickListener(this); - - updateSettingsVisibility(); - } - - /** - * MUST be called on UI thread. - */ - public void refresh() { - List appInfos = mPaymentBackend.getPaymentAppInfos(); - PaymentAppInfo defaultApp = mPaymentBackend.getDefaultApp(); - if (appInfos != null) { - PaymentAppInfo[] apps = appInfos.toArray(new PaymentAppInfo[appInfos.size()]); - mAdapter.updateApps(apps, defaultApp); + if (mListener != null) { + mListener.onBindViewHolder(view); } - setTitle(R.string.nfc_payment_default); - if (defaultApp != null) { - setSummary(defaultApp.label); - } else { - setSummary(mContext.getString(R.string.nfc_payment_default_not_set)); - } - updateSettingsVisibility(); } @Override @@ -97,122 +66,8 @@ public class NfcPaymentPreference extends CustomDialogPreference implements DialogInterface.OnClickListener listener) { super.onPrepareDialogBuilder(builder, listener); - builder.setSingleChoiceItems(mAdapter, 0, listener); - } - - @Override - public void onPaymentAppsChanged() { - refresh(); - } - - @Override - public void onClick(View view) { - PaymentAppInfo defaultAppInfo = mPaymentBackend.getDefaultApp(); - if (defaultAppInfo != null && defaultAppInfo.settingsComponent != null) { - Intent settingsIntent = new Intent(Intent.ACTION_MAIN); - settingsIntent.setComponent(defaultAppInfo.settingsComponent); - settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - try { - mContext.startActivity(settingsIntent); - } catch (ActivityNotFoundException e) { - Log.e(TAG, "Settings activity not found."); - } - } - } - - void updateSettingsVisibility() { - if (mSettingsButtonView != null) { - PaymentAppInfo defaultApp = mPaymentBackend.getDefaultApp(); - if (defaultApp == null || defaultApp.settingsComponent == null) { - mSettingsButtonView.setVisibility(View.GONE); - } else { - mSettingsButtonView.setVisibility(View.VISIBLE); - - } - } - } - - class NfcPaymentAdapter extends BaseAdapter implements CompoundButton.OnCheckedChangeListener, - View.OnClickListener { - // Only modified on UI thread - private PaymentAppInfo[] appInfos; - - public NfcPaymentAdapter() { - } - - public void updateApps(PaymentAppInfo[] appInfos, PaymentAppInfo currentDefault) { - // Clone app infos, only add those with a banner - this.appInfos = appInfos; - notifyDataSetChanged(); - } - - @Override - public int getCount() { - return appInfos.length; - } - - @Override - public PaymentAppInfo getItem(int i) { - return appInfos[i]; - } - - @Override - public long getItemId(int i) { - return appInfos[i].componentName.hashCode(); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - ViewHolder holder; - PaymentAppInfo appInfo = appInfos[position]; - if (convertView == null) { - convertView = mLayoutInflater.inflate( - R.layout.nfc_payment_option, parent, false); - holder = new ViewHolder(); - holder.imageView = (ImageView) convertView.findViewById(R.id.banner); - holder.radioButton = (RadioButton) convertView.findViewById(R.id.button); - convertView.setTag(holder); - } else { - holder = (ViewHolder) convertView.getTag(); - } - holder.imageView.setImageDrawable(appInfo.banner); - holder.imageView.setTag(appInfo); - holder.imageView.setContentDescription(appInfo.label); - holder.imageView.setOnClickListener(this); - - // Prevent checked callback getting called on recycled views - holder.radioButton.setOnCheckedChangeListener(null); - holder.radioButton.setChecked(appInfo.isDefault); - holder.radioButton.setContentDescription(appInfo.label); - holder.radioButton.setOnCheckedChangeListener(this); - holder.radioButton.setTag(appInfo); - return convertView; - } - - public class ViewHolder { - public ImageView imageView; - public RadioButton radioButton; - } - - @Override - public void onCheckedChanged(CompoundButton compoundButton, boolean b) { - PaymentAppInfo appInfo = (PaymentAppInfo) compoundButton.getTag(); - makeDefault(appInfo); - } - - @Override - public void onClick(View view) { - PaymentAppInfo appInfo = (PaymentAppInfo) view.getTag(); - makeDefault(appInfo); - } - - void makeDefault(PaymentAppInfo appInfo) { - if (!appInfo.isDefault) { - mPaymentBackend.setDefaultPaymentApp(appInfo.componentName); - } - Dialog dialog = getDialog(); - if (dialog != null) - dialog.dismiss(); + if (mListener != null) { + mListener.onPrepareDialogBuilder(builder, listener); } } } diff --git a/src/com/android/settings/nfc/NfcPaymentPreferenceController.java b/src/com/android/settings/nfc/NfcPaymentPreferenceController.java new file mode 100644 index 00000000000..4f2f755ad7d --- /dev/null +++ b/src/com/android/settings/nfc/NfcPaymentPreferenceController.java @@ -0,0 +1,257 @@ +/* + * Copyright (C) 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.nfc; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.ActivityNotFoundException; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.CompoundButton; +import android.widget.ImageView; +import android.widget.RadioButton; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.nfc.PaymentBackend.PaymentAppInfo; +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; + +import java.util.List; + +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import androidx.preference.PreferenceViewHolder; + +public class NfcPaymentPreferenceController extends BasePreferenceController implements + PaymentBackend.Callback, View.OnClickListener, NfcPaymentPreference.Listener, + LifecycleObserver, OnStart, OnStop { + + private static final String TAG = "NfcPaymentController"; + + private final NfcPaymentAdapter mAdapter; + private PaymentBackend mPaymentBackend; + private NfcPaymentPreference mPreference; + private ImageView mSettingsButtonView; + + public NfcPaymentPreferenceController(Context context, String key) { + super(context, key); + mAdapter = new NfcPaymentAdapter(context); + } + + public void setPaymentBackend(PaymentBackend backend) { + mPaymentBackend = backend; + } + + @Override + public void onStart() { + if (mPaymentBackend != null) { + mPaymentBackend.registerCallback(this); + } + } + + @Override + public void onStop() { + if (mPaymentBackend != null) { + mPaymentBackend.unregisterCallback(this); + } + } + + @Override + public int getAvailabilityStatus() { + final PackageManager pm = mContext.getPackageManager(); + if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC)) { + return DISABLED_UNSUPPORTED; + } + if (mPaymentBackend == null) { + mPaymentBackend = new PaymentBackend(mContext); + } + final List appInfos = mPaymentBackend.getPaymentAppInfos(); + return (appInfos != null && !appInfos.isEmpty()) + ? AVAILABLE + : DISABLED_UNSUPPORTED; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = (NfcPaymentPreference) screen.findPreference(getPreferenceKey()); + if (mPreference != null) { + mPreference.initialize(this); + } + } + + @Override + public void onBindViewHolder(PreferenceViewHolder view) { + mSettingsButtonView = (ImageView) view.findViewById(R.id.settings_button); + mSettingsButtonView.setOnClickListener(this); + + updateSettingsVisibility(); + } + + @Override + public void updateState(Preference preference) { + final List appInfos = mPaymentBackend.getPaymentAppInfos(); + if (appInfos != null) { + final PaymentAppInfo[] apps = appInfos.toArray(new PaymentAppInfo[appInfos.size()]); + mAdapter.updateApps(apps); + } + super.updateState(preference); + updateSettingsVisibility(); + } + + @Override + public CharSequence getSummary() { + final PaymentAppInfo defaultApp = mPaymentBackend.getDefaultApp(); + if (defaultApp != null) { + return defaultApp.label; + } else { + return mContext.getText(R.string.nfc_payment_default_not_set); + } + } + + @Override + public void onPrepareDialogBuilder(AlertDialog.Builder builder, + DialogInterface.OnClickListener listener) { + builder.setSingleChoiceItems(mAdapter, 0, listener); + } + + @Override + public void onPaymentAppsChanged() { + updateState(mPreference); + } + + @Override + public void onClick(View view) { + final PaymentAppInfo defaultAppInfo = mPaymentBackend.getDefaultApp(); + if (defaultAppInfo != null && defaultAppInfo.settingsComponent != null) { + final Intent settingsIntent = new Intent(Intent.ACTION_MAIN); + settingsIntent.setComponent(defaultAppInfo.settingsComponent); + settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(settingsIntent); + } catch (ActivityNotFoundException e) { + Log.e(TAG, "Settings activity not found."); + } + } + } + + private void updateSettingsVisibility() { + if (mSettingsButtonView != null) { + final PaymentAppInfo defaultApp = mPaymentBackend.getDefaultApp(); + if (defaultApp == null || defaultApp.settingsComponent == null) { + mSettingsButtonView.setVisibility(View.GONE); + } else { + mSettingsButtonView.setVisibility(View.VISIBLE); + } + } + } + + private class NfcPaymentAdapter extends BaseAdapter implements + CompoundButton.OnCheckedChangeListener, View.OnClickListener { + private final LayoutInflater mLayoutInflater; + + // Only modified on UI thread + private PaymentAppInfo[] appInfos; + + public NfcPaymentAdapter(Context context) { + mLayoutInflater = (LayoutInflater) context.getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + } + + public void updateApps(PaymentAppInfo[] appInfos) { + // Clone app infos, only add those with a banner + this.appInfos = appInfos; + notifyDataSetChanged(); + } + + @Override + public int getCount() { + return (appInfos != null) ? appInfos.length : 0; + } + + @Override + public PaymentAppInfo getItem(int i) { + return appInfos[i]; + } + + @Override + public long getItemId(int i) { + return appInfos[i].componentName.hashCode(); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + ViewHolder holder; + final PaymentAppInfo appInfo = appInfos[position]; + if (convertView == null) { + convertView = mLayoutInflater.inflate( + R.layout.nfc_payment_option, parent, false); + holder = new ViewHolder(); + holder.imageView = convertView.findViewById(R.id.banner); + holder.radioButton = convertView.findViewById(R.id.button); + convertView.setTag(holder); + } else { + holder = (ViewHolder) convertView.getTag(); + } + holder.imageView.setImageDrawable(appInfo.banner); + holder.imageView.setTag(appInfo); + holder.imageView.setContentDescription(appInfo.label); + holder.imageView.setOnClickListener(this); + + // Prevent checked callback getting called on recycled views + holder.radioButton.setOnCheckedChangeListener(null); + holder.radioButton.setChecked(appInfo.isDefault); + holder.radioButton.setContentDescription(appInfo.label); + holder.radioButton.setOnCheckedChangeListener(this); + holder.radioButton.setTag(appInfo); + return convertView; + } + + private class ViewHolder { + public ImageView imageView; + public RadioButton radioButton; + } + + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean b) { + PaymentAppInfo appInfo = (PaymentAppInfo) compoundButton.getTag(); + makeDefault(appInfo); + } + + @Override + public void onClick(View view) { + PaymentAppInfo appInfo = (PaymentAppInfo) view.getTag(); + makeDefault(appInfo); + } + + private void makeDefault(PaymentAppInfo appInfo) { + if (!appInfo.isDefault) { + mPaymentBackend.setDefaultPaymentApp(appInfo.componentName); + } + final Dialog dialog = mPreference.getDialog(); + if (dialog != null) { + dialog.dismiss(); + } + } + } +} \ No newline at end of file diff --git a/src/com/android/settings/nfc/PaymentBackend.java b/src/com/android/settings/nfc/PaymentBackend.java index 91cd96cd0b0..67ea6bdf7c6 100644 --- a/src/com/android/settings/nfc/PaymentBackend.java +++ b/src/com/android/settings/nfc/PaymentBackend.java @@ -25,7 +25,9 @@ import android.nfc.NfcAdapter; import android.nfc.cardemulation.ApduServiceInfo; import android.nfc.cardemulation.CardEmulation; import android.os.Handler; +import android.os.Looper; import android.os.Message; +import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; @@ -57,7 +59,7 @@ public class PaymentBackend { // Fields below only modified on UI thread private ArrayList mAppInfos; private PaymentAppInfo mDefaultAppInfo; - private ArrayList mCallbacks = new ArrayList(); + private ArrayList mCallbacks = new ArrayList<>(); public PaymentBackend(Context context) { mContext = context; @@ -102,7 +104,8 @@ public class PaymentBackend { appInfo.componentName = service.getComponent(); String settingsActivity = service.getSettingsActivityName(); if (settingsActivity != null) { - appInfo.settingsComponent = new ComponentName(appInfo.componentName.getPackageName(), + appInfo.settingsComponent = new ComponentName( + appInfo.componentName.getPackageName(), settingsActivity); } else { appInfo.settingsComponent = null; @@ -162,7 +165,7 @@ public class PaymentBackend { void setForegroundMode(boolean foreground) { Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.NFC_PAYMENT_FOREGROUND, foreground ? 1 : 0) ; + Settings.Secure.NFC_PAYMENT_FOREGROUND, foreground ? 1 : 0); } ComponentName getDefaultPaymentApp() { @@ -182,14 +185,23 @@ public class PaymentBackend { refresh(); } - private final Handler mHandler = new Handler() { - @Override - public void dispatchMessage(Message msg) { - refresh(); - } - }; - private class SettingsPackageMonitor extends PackageMonitor { + private Handler mHandler; + + @Override + public void register(Context context, Looper thread, UserHandle user, + boolean externalStorage) { + if (mHandler == null) { + mHandler = new Handler(thread) { + @Override + public void dispatchMessage(Message msg) { + refresh(); + } + }; + } + super.register(context, thread, user, externalStorage); + } + @Override public void onPackageAdded(String packageName, int uid) { mHandler.obtainMessage().sendToTarget(); @@ -210,4 +222,4 @@ public class PaymentBackend { mHandler.obtainMessage().sendToTarget(); } } -} +} \ No newline at end of file diff --git a/src/com/android/settings/nfc/PaymentSettings.java b/src/com/android/settings/nfc/PaymentSettings.java index e3cf697fd2b..82335814581 100644 --- a/src/com/android/settings/nfc/PaymentSettings.java +++ b/src/com/android/settings/nfc/PaymentSettings.java @@ -19,10 +19,8 @@ package com.android.settings.nfc; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.os.Bundle; -import androidx.preference.PreferenceManager; -import androidx.preference.PreferenceScreen; +import android.provider.SearchIndexableResource; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; @@ -31,23 +29,25 @@ import android.view.ViewGroup; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settings.R; -import com.android.settings.SettingsPreferenceFragment; +import com.android.settings.dashboard.DashboardFragment; import com.android.settings.search.BaseSearchIndexProvider; -import com.android.settings.search.Indexable; -import com.android.settings.search.SearchIndexableRaw; import com.android.settingslib.search.SearchIndexable; -import java.util.ArrayList; +import java.util.Arrays; import java.util.List; + @SearchIndexable -public class PaymentSettings extends SettingsPreferenceFragment implements Indexable { +public class PaymentSettings extends DashboardFragment { public static final String TAG = "PaymentSettings"; - static final String PAYMENT_KEY = "payment"; - private PaymentBackend mPaymentBackend; + @Override + protected String getLogTag() { + return TAG; + } + @Override public int getMetricsCategory() { return MetricsEvent.NFC_PAYMENT; @@ -59,24 +59,13 @@ public class PaymentSettings extends SettingsPreferenceFragment implements Index } @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - + public void onAttach(Context context) { + super.onAttach(context); mPaymentBackend = new PaymentBackend(getActivity()); setHasOptionsMenu(true); - final PreferenceScreen screen = getPreferenceScreen(); - - List appInfos = mPaymentBackend.getPaymentAppInfos(); - if (appInfos != null && appInfos.size() > 0) { - NfcPaymentPreference preference = - new NfcPaymentPreference(getPrefContext(), mPaymentBackend); - preference.setKey(PAYMENT_KEY); - screen.addPreference(preference); - NfcForegroundPreference foreground = new NfcForegroundPreference(getPrefContext(), - mPaymentBackend); - screen.addPreference(foreground); - } + use(NfcPaymentPreferenceController.class).setPaymentBackend(mPaymentBackend); + use(NfcForegroundPreferenceController.class).setPaymentBackend(mPaymentBackend); } @Override @@ -111,31 +100,19 @@ public class PaymentSettings extends SettingsPreferenceFragment implements Index } public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = - new BaseSearchIndexProvider() { - @Override - public List getRawDataToIndex(Context context, boolean enabled) { - final List result = new ArrayList(); - final Resources res = context.getResources(); - - // Add fragment title - SearchIndexableRaw data = new SearchIndexableRaw(context); - data.key = PAYMENT_KEY; - data.title = res.getString(R.string.nfc_payment_settings_title); - data.screenTitle = res.getString(R.string.nfc_payment_settings_title); - data.keywords = res.getString(R.string.keywords_payment_settings); - result.add(data); - return result; - } - - @Override - public List getNonIndexableKeys(Context context) { - final List nonVisibleKeys = super.getNonIndexableKeys(context); - final PackageManager pm = context.getPackageManager(); - if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) { - return nonVisibleKeys; + new BaseSearchIndexProvider() { + @Override + public List getXmlResourcesToIndex(Context context, + boolean enabled) { + final SearchIndexableResource sir = new SearchIndexableResource(context); + sir.xmlResId = R.xml.nfc_payment_settings; + return Arrays.asList(sir); } - nonVisibleKeys.add(PAYMENT_KEY); - return nonVisibleKeys; - } - }; -} + + @Override + protected boolean isPageSearchEnabled(Context context) { + final PackageManager pm = context.getPackageManager(); + return pm.hasSystemFeature(PackageManager.FEATURE_NFC); + } + }; +} \ No newline at end of file diff --git a/src/com/android/settings/notification/SoundSettings.java b/src/com/android/settings/notification/SoundSettings.java index bb312f8f692..228ced12cdd 100644 --- a/src/com/android/settings/notification/SoundSettings.java +++ b/src/com/android/settings/notification/SoundSettings.java @@ -213,6 +213,8 @@ public class SoundSettings extends DashboardFragment { new DialPadTonePreferenceController(context, fragment, lifecycle); final ScreenLockSoundPreferenceController screenLockSoundPreferenceController = new ScreenLockSoundPreferenceController(context, fragment, lifecycle); + final ChargingSoundPreferenceController chargingSoundPreferenceController = + new ChargingSoundPreferenceController(context, fragment, lifecycle); final DockingSoundPreferenceController dockingSoundPreferenceController = new DockingSoundPreferenceController(context, fragment, lifecycle); final TouchSoundPreferenceController touchSoundPreferenceController = @@ -228,6 +230,7 @@ public class SoundSettings extends DashboardFragment { controllers.add(dialPadTonePreferenceController); controllers.add(screenLockSoundPreferenceController); + controllers.add(chargingSoundPreferenceController); controllers.add(dockingSoundPreferenceController); controllers.add(touchSoundPreferenceController); controllers.add(vibrateOnTouchPreferenceController); @@ -238,6 +241,7 @@ public class SoundSettings extends DashboardFragment { "other_sounds_and_vibrations_category").setChildren( Arrays.asList(dialPadTonePreferenceController, screenLockSoundPreferenceController, + chargingSoundPreferenceController, dockingSoundPreferenceController, touchSoundPreferenceController, vibrateOnTouchPreferenceController, diff --git a/tests/robotests/src/com/android/settings/backup/AutoRestorePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/backup/AutoRestorePreferenceControllerTest.java index 6a3288c1287..9a4e167576c 100644 --- a/tests/robotests/src/com/android/settings/backup/AutoRestorePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/backup/AutoRestorePreferenceControllerTest.java @@ -19,7 +19,6 @@ package com.android.settings.backup; import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import androidx.preference.SwitchPreference; import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -32,6 +31,8 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import androidx.preference.SwitchPreference; + @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = {ShadowPrivacySettingsUtils.class}) public class AutoRestorePreferenceControllerTest { @@ -44,7 +45,7 @@ public class AutoRestorePreferenceControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - mPSCD = new PrivacySettingsConfigData(); + mPSCD = PrivacySettingsConfigData.getInstance(); mController = new AutoRestorePreferenceController(mContext, PrivacySettingsUtils.AUTO_RESTORE); mPreference = new SwitchPreference(mContext); @@ -59,7 +60,7 @@ public class AutoRestorePreferenceControllerTest { public void updateState_backupEnabled_prefShouldBeEnabled() { mPSCD.setBackupEnabled(true); mPSCD.setBackupGray(false); - mController.setPrivacySettingsConfigData(mPSCD); + mController.updateState(mPreference); assertThat(mPreference.isEnabled()).isTrue(); } diff --git a/tests/robotests/src/com/android/settings/backup/BackupDataPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/backup/BackupDataPreferenceControllerTest.java index 73a9bc5525a..7cfe9c740fd 100644 --- a/tests/robotests/src/com/android/settings/backup/BackupDataPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/backup/BackupDataPreferenceControllerTest.java @@ -19,8 +19,6 @@ package com.android.settings.backup; import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import android.os.UserManager; -import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; @@ -34,6 +32,8 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import androidx.preference.Preference; + @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = {ShadowPrivacySettingsUtils.class}) public class BackupDataPreferenceControllerTest { @@ -46,7 +46,7 @@ public class BackupDataPreferenceControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - mPSCD = new PrivacySettingsConfigData(); + mPSCD = PrivacySettingsConfigData.getInstance(); mController = new BackupDataPreferenceController(mContext, PrivacySettingsUtils.BACKUP_DATA); mPreference = new Preference(mContext); @@ -61,7 +61,7 @@ public class BackupDataPreferenceControllerTest { public void updateState_backupEnabled_prefShouldBeEnabled() { mPSCD.setBackupEnabled(true); mPSCD.setBackupGray(false); - mController.setPrivacySettingsConfigData(mPSCD); + mController.updateState(mPreference); assertThat(mPreference.isEnabled()).isTrue(); } @@ -70,7 +70,7 @@ public class BackupDataPreferenceControllerTest { public void updateState_backupEnabled_prefShouldDisplayOnSummary() { mPSCD.setBackupEnabled(true); mPSCD.setBackupGray(false); - mController.setPrivacySettingsConfigData(mPSCD); + mController.updateState(mPreference); assertThat(mPreference.getSummary()) .isEqualTo(mContext.getString(R.string.accessibility_feature_state_on)); @@ -80,7 +80,7 @@ public class BackupDataPreferenceControllerTest { public void updateState_backupDisabled_prefShouldDisplayOffSummary() { mPSCD.setBackupEnabled(false); mPSCD.setBackupGray(false); - mController.setPrivacySettingsConfigData(mPSCD); + mController.updateState(mPreference); assertThat(mPreference.getSummary()) .isEqualTo(mContext.getString(R.string.accessibility_feature_state_off)); diff --git a/tests/robotests/src/com/android/settings/backup/ConfigureAccountPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/backup/ConfigureAccountPreferenceControllerTest.java index 7ddd95adf3c..306088356e8 100644 --- a/tests/robotests/src/com/android/settings/backup/ConfigureAccountPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/backup/ConfigureAccountPreferenceControllerTest.java @@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.content.Intent; -import androidx.preference.Preference; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; @@ -35,6 +34,8 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import androidx.preference.Preference; + @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = {ShadowPrivacySettingsUtils.class}) public class ConfigureAccountPreferenceControllerTest { @@ -51,7 +52,7 @@ public class ConfigureAccountPreferenceControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - mPSCD = new PrivacySettingsConfigData(); + mPSCD = PrivacySettingsConfigData.getInstance(); mController = new ConfigureAccountPreferenceController(mContext, PrivacySettingsUtils.CONFIGURE_ACCOUNT); mPreference = new Preference(mContext); @@ -68,7 +69,7 @@ public class ConfigureAccountPreferenceControllerTest { mPSCD.setBackupEnabled(true); mPSCD.setBackupGray(false); mPSCD.setConfigIntent(mIntent); - mController.setPrivacySettingsConfigData(mPSCD); + mController.updateState(mPreference); assertThat(mPreference.isEnabled()).isTrue(); } @@ -80,7 +81,7 @@ public class ConfigureAccountPreferenceControllerTest { mPSCD.setBackupGray(false); mPSCD.setConfigIntent(mIntent); mPSCD.setConfigSummary(null); - mController.setPrivacySettingsConfigData(mPSCD); + mController.updateState(mPreference); assertThat(mPreference.getSummary()) .isEqualTo(mContext.getString(R.string.backup_configure_account_default_summary)); @@ -93,7 +94,7 @@ public class ConfigureAccountPreferenceControllerTest { mPSCD.setBackupGray(false); mPSCD.setConfigIntent(mIntent); mPSCD.setConfigSummary(mTestSummary); - mController.setPrivacySettingsConfigData(mPSCD); + mController.updateState(mPreference); assertThat(mPreference.getSummary()).isEqualTo(mTestSummary); } diff --git a/tests/robotests/src/com/android/settings/backup/DataManagementPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/backup/DataManagementPreferenceControllerTest.java index 36e20459935..f192a8bdff4 100644 --- a/tests/robotests/src/com/android/settings/backup/DataManagementPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/backup/DataManagementPreferenceControllerTest.java @@ -20,7 +20,6 @@ import static com.google.common.truth.Truth.assertThat; import android.content.Context; import android.content.Intent; -import androidx.preference.Preference; import com.android.settings.core.BasePreferenceController; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -34,6 +33,8 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; +import androidx.preference.Preference; + @RunWith(SettingsRobolectricTestRunner.class) @Config(shadows = {ShadowPrivacySettingsUtils.class}) public class DataManagementPreferenceControllerTest { @@ -56,7 +57,7 @@ public class DataManagementPreferenceControllerTest { public void setUp() { MockitoAnnotations.initMocks(this); mContext = RuntimeEnvironment.application; - mPSCD = new PrivacySettingsConfigData(); + mPSCD = PrivacySettingsConfigData.getInstance(); mController = new DataManagementPreferenceController(mContext, KEY); mPreference = new Preference(mContext); mTitle = "Title"; @@ -68,26 +69,25 @@ public class DataManagementPreferenceControllerTest { mPSCD.setBackupGray(false); mPSCD.setManageIntent(mIntent); mPSCD.setManageLabel(mTitle); - mController.setPrivacySettingsConfigData(mPSCD); mController.updateState(mPreference); assertThat(mPreference.getTitle()) .isEqualTo(mTitle); } @Test - public void getAvailabilityStatus_isAdmiUser_backupEnabled_hadManageIntent_shouldBeAvailable() { + public void getAvailabilityStatus_isAdmin_backupEnabled_hadManageIntent_shouldBeAvailable() { ShadowPrivacySettingsUtils.setIsAdminUser(true); mPSCD.setBackupEnabled(true); mPSCD.setBackupGray(false); mPSCD.setManageIntent(mIntent); mPSCD.setManageLabel(mTitle); - mController.setPrivacySettingsConfigData(mPSCD); + assertThat(mController.getAvailabilityStatus()) .isEqualTo(BasePreferenceController.AVAILABLE); } @Test - public void getAvailabilityStatus_isnotAdmiUser_shouldBeDisabledForUser() { + public void getAvailabilityStatus_isNotAdminUser_shouldBeDisabledForUser() { ShadowPrivacySettingsUtils.setIsAdminUser(false); assertThat(mController.getAvailabilityStatus()) .isEqualTo(BasePreferenceController.DISABLED_FOR_USER); @@ -95,13 +95,13 @@ public class DataManagementPreferenceControllerTest { @Test public void - getAvailabilityStatus_isAdmiUser_backupEnabled_nullManageIntent_shouldBeDisabledUnsupported() { + getAvailabilityStatus_isAdminUser_backupEnabled_nullManageIntent_shouldBeDisabledUnsupported() { ShadowPrivacySettingsUtils.setIsAdminUser(true); mPSCD.setBackupEnabled(true); mPSCD.setBackupGray(false); mPSCD.setManageIntent(null); mPSCD.setManageLabel(mTitle); - mController.setPrivacySettingsConfigData(mPSCD); + assertThat(mController.getAvailabilityStatus()) .isEqualTo(BasePreferenceController.DISABLED_UNSUPPORTED); } diff --git a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java index db5c969ec24..78d3a09adf5 100644 --- a/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java +++ b/tests/robotests/src/com/android/settings/dashboard/DashboardFeatureProviderImplTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; @@ -214,6 +215,15 @@ public class DashboardFeatureProviderImplTest { .startActivityForResultAsUser(any(Intent.class), anyInt(), any(UserHandle.class)); } + @Test + public void bindPreference_nullPreference_shouldIgnore() { + final Tile tile = mock(Tile.class); + mImpl.bindPreferenceToTile(mActivity, MetricsProto.MetricsEvent.VIEW_UNKNOWN, + null, tile, "123", Preference.DEFAULT_ORDER); + + verifyZeroInteractions(tile); + } + @Test public void bindPreference_withNullKeyNullPriority_shouldGenerateKeyAndPriority() { final Preference preference = new Preference(RuntimeEnvironment.application); diff --git a/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilesTest.java b/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilesTest.java new file mode 100644 index 00000000000..85c1cb522d2 --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/qstile/DevelopmentTilesTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 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.qstile; + +import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + +import android.service.quicksettings.Tile; + +import com.android.settings.testutils.SettingsRobolectricTestRunner; +import com.android.settingslib.development.DevelopmentSettingsEnabler; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.Robolectric; + +@RunWith(SettingsRobolectricTestRunner.class) +public class DevelopmentTilesTest { + + @Mock + private Tile mTile; + private DevelopmentTiles mService; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mService = spy(Robolectric.setupService(DevelopmentTiles.ShowLayout.class)); + doReturn(mTile).when(mService).getQsTile(); + } + + @Test + public void refresh_devOptionIsDisabled_shouldResetTileValue() { + DevelopmentSettingsEnabler.setDevelopmentSettingsEnabled(mService, false); + mService.setIsEnabled(true); + + mService.refresh(); + + assertThat(mService.isEnabled()).isFalse(); + } +} diff --git a/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java index d8c44a2544e..0fb041b124c 100644 --- a/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/nfc/AndroidBeamPreferenceControllerTest.java @@ -17,7 +17,6 @@ package com.android.settings.nfc; import static com.google.common.truth.Truth.assertThat; - import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -27,7 +26,6 @@ import android.nfc.NfcManager; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; -import androidx.preference.PreferenceScreen; import com.android.settings.testutils.SettingsRobolectricTestRunner; import com.android.settingslib.RestrictedLockUtils; @@ -44,6 +42,8 @@ import org.robolectric.util.ReflectionHelpers; import java.util.ArrayList; import java.util.List; +import androidx.preference.PreferenceScreen; + @RunWith(SettingsRobolectricTestRunner.class) public class AndroidBeamPreferenceControllerTest { diff --git a/tests/robotests/src/com/android/settings/nfc/NfcForegroundPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/NfcForegroundPreferenceControllerTest.java new file mode 100644 index 00000000000..b3e857f8662 --- /dev/null +++ b/tests/robotests/src/com/android/settings/nfc/NfcForegroundPreferenceControllerTest.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 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.nfc; + +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.Context; +import android.content.pm.PackageManager; + +import com.android.settings.R; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +import java.util.ArrayList; + +import androidx.preference.DropDownPreference; +import androidx.preference.PreferenceScreen; + +@RunWith(SettingsRobolectricTestRunner.class) +public class NfcForegroundPreferenceControllerTest { + + private static final String PREF_KEY = PaymentSettingsTest.FOREGROUND_KEY; + + @Mock + private PaymentBackend mPaymentBackend; + @Mock + private PreferenceScreen mScreen; + @Mock + private PackageManager mManager; + + private Context mContext; + private DropDownPreference mPreference; + private NfcForegroundPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + when(mContext.getPackageManager()).thenReturn(mManager); + mController = new NfcForegroundPreferenceController(mContext, PREF_KEY); + mPreference = new DropDownPreference(mContext); + when(mScreen.findPreference(PREF_KEY)).thenReturn(mPreference); + } + + @Test + public void getAvailabilityStatus_noNFC_DISABLED() { + when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(false); + + assertThat(mController.getAvailabilityStatus()) + .isNotEqualTo(NfcForegroundPreferenceController.AVAILABLE); + } + + @Test + public void getAvailabilityStatus_noPaymentBackend_DISABLED() { + when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true); + + assertThat(mController.getAvailabilityStatus()) + .isNotEqualTo(NfcForegroundPreferenceController.AVAILABLE); + } + + @Test + public void getAvailabilityStatus_noPaymentApps_DISABLED() { + when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true); + mController.setPaymentBackend(mPaymentBackend); + when(mPaymentBackend.getPaymentAppInfos()).thenReturn(null); + + assertThat(mController.getAvailabilityStatus()) + .isNotEqualTo(NfcForegroundPreferenceController.AVAILABLE); + + when(mPaymentBackend.getPaymentAppInfos()).thenReturn(new ArrayList<>()); + + assertThat(mController.getAvailabilityStatus()) + .isNotEqualTo(NfcForegroundPreferenceController.AVAILABLE); + } + + private void initPaymentApps() { + when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true); + mController.setPaymentBackend(mPaymentBackend); + final ArrayList appInfos = new ArrayList<>(); + appInfos.add(new PaymentBackend.PaymentAppInfo()); + when(mPaymentBackend.getPaymentAppInfos()).thenReturn(appInfos); + } + + @Test + public void getAvailabilityStatus_hasPaymentApps_AVAILABLE() { + initPaymentApps(); + + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(NfcForegroundPreferenceController.AVAILABLE); + } + + @Test + public void onStart_shouldRegisterCallback() { + mController.setPaymentBackend(mPaymentBackend); + + mController.onStart(); + + verify(mPaymentBackend).registerCallback(mController); + } + + @Test + public void onStop_shouldUnregisterCallback() { + mController.setPaymentBackend(mPaymentBackend); + mController.onStart(); + + mController.onStop(); + + verify(mPaymentBackend).unregisterCallback(mController); + } + + @Test + public void changeOptions_shouldUpdateEntryAndSummary() { + initPaymentApps(); + mController.displayPreference(mScreen); + mController.onPaymentAppsChanged(); + + final CharSequence favorDefault = mContext.getText(R.string.nfc_payment_favor_default); + final CharSequence favorOpen = mContext.getText(R.string.nfc_payment_favor_open); + + assertThat(mPreference.getEntry()).isEqualTo(favorDefault); + assertThat(mPreference.getSummary()).isEqualTo(favorDefault); + + mPreference.setValueIndex(0); + mPreference.callChangeListener(mPreference.getEntryValues()[0]); + verify(mPaymentBackend).setForegroundMode(true); + assertThat(mPreference.getEntry()).isEqualTo(favorOpen); + assertThat(mPreference.getSummary()).isEqualTo(favorOpen); + + mPreference.setValueIndex(1); + mPreference.callChangeListener(mPreference.getEntryValues()[1]); + verify(mPaymentBackend).setForegroundMode(false); + assertThat(mPreference.getEntry()).isEqualTo(favorDefault); + assertThat(mPreference.getSummary()).isEqualTo(favorDefault); + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/nfc/NfcForegroundPreferenceTest.java b/tests/robotests/src/com/android/settings/nfc/NfcForegroundPreferenceTest.java deleted file mode 100644 index 4d40b122368..00000000000 --- a/tests/robotests/src/com/android/settings/nfc/NfcForegroundPreferenceTest.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 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.nfc; - -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.content.Context; -import androidx.preference.PreferenceManager; -import androidx.preference.PreferenceScreen; - -import com.android.settings.R; -import com.android.settings.testutils.SettingsRobolectricTestRunner; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.RuntimeEnvironment; - -@RunWith(SettingsRobolectricTestRunner.class) -public class NfcForegroundPreferenceTest { - @Mock - private PaymentBackend mPaymentBackend; - - private Context mContext; - private PreferenceScreen mScreen; - private NfcForegroundPreference mPreference; - - @Before - public void setUp() { - MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; - mScreen = spy(new PreferenceScreen(mContext, null)); - when(mScreen.getPreferenceManager()).thenReturn(mock(PreferenceManager.class)); - when(mPaymentBackend.isForegroundMode()).thenReturn(false); - mPreference = new NfcForegroundPreference(mContext, mPaymentBackend); - mScreen.addPreference(mPreference); - } - - @Test - public void testTogglingMode() { - String nfc_payment_favor_default = mContext.getString(R.string.nfc_payment_favor_default); - String nfc_payment_favor_open = mContext.getString(R.string.nfc_payment_favor_open); - - assertThat(mPreference.getEntry()).isEqualTo(nfc_payment_favor_default); - assertThat(mPreference.getSummary()).isEqualTo(nfc_payment_favor_default); - - mPreference.setValueIndex(0); - mPreference.callChangeListener(mPreference.getEntryValues()[0]); - verify(mPaymentBackend).setForegroundMode(true); - assertThat(mPreference.getEntry()).isEqualTo(nfc_payment_favor_open); - assertThat(mPreference.getSummary()).isEqualTo(nfc_payment_favor_open); - - mPreference.setValueIndex(1); - mPreference.callChangeListener(mPreference.getEntryValues()[1]); - verify(mPaymentBackend).setForegroundMode(false); - assertThat(mPreference.getEntry()).isEqualTo(nfc_payment_favor_default); - assertThat(mPreference.getSummary()).isEqualTo(nfc_payment_favor_default); - } -} diff --git a/tests/robotests/src/com/android/settings/nfc/NfcPaymentPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/NfcPaymentPreferenceControllerTest.java new file mode 100644 index 00000000000..a23822f74b1 --- /dev/null +++ b/tests/robotests/src/com/android/settings/nfc/NfcPaymentPreferenceControllerTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 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.nfc; + +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.Context; +import android.content.pm.PackageManager; + +import com.android.settings.R; +import com.android.settings.nfc.PaymentBackend.PaymentAppInfo; +import com.android.settings.testutils.SettingsRobolectricTestRunner; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; + +import java.util.ArrayList; + +import androidx.preference.PreferenceScreen; + +@RunWith(SettingsRobolectricTestRunner.class) +public class NfcPaymentPreferenceControllerTest { + + private static final String PREF_KEY = PaymentSettingsTest.PAYMENT_KEY; + + @Mock + private PaymentBackend mPaymentBackend; + @Mock + private PreferenceScreen mScreen; + @Mock + private PackageManager mManager; + + private Context mContext; + private NfcPaymentPreference mPreference; + private NfcPaymentPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + when(mContext.getPackageManager()).thenReturn(mManager); + mController = new NfcPaymentPreferenceController(mContext, PREF_KEY); + mPreference = spy(new NfcPaymentPreference(mContext, null)); + when(mScreen.findPreference(PREF_KEY)).thenReturn(mPreference); + } + + @Test + public void getAvailabilityStatus_noNFC_DISABLED() { + when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(false); + + assertThat(mController.getAvailabilityStatus()) + .isNotEqualTo(NfcPaymentPreferenceController.AVAILABLE); + } + + @Test + public void getAvailabilityStatus_noPaymentApps_DISABLED() { + when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true); + mController.setPaymentBackend(mPaymentBackend); + when(mPaymentBackend.getPaymentAppInfos()).thenReturn(null); + + assertThat(mController.getAvailabilityStatus()) + .isNotEqualTo(NfcPaymentPreferenceController.AVAILABLE); + + when(mPaymentBackend.getPaymentAppInfos()).thenReturn(new ArrayList<>()); + + assertThat(mController.getAvailabilityStatus()) + .isNotEqualTo(NfcPaymentPreferenceController.AVAILABLE); + } + + @Test + public void getAvailabilityStatus_hasPaymentApps_AVAILABLE() { + when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true); + mController.setPaymentBackend(mPaymentBackend); + final ArrayList appInfos = new ArrayList<>(); + appInfos.add(new PaymentAppInfo()); + when(mPaymentBackend.getPaymentAppInfos()).thenReturn(appInfos); + + assertThat(mController.getAvailabilityStatus()) + .isEqualTo(NfcPaymentPreferenceController.AVAILABLE); + } + + @Test + public void onStart_shouldRegisterCallback() { + mController.setPaymentBackend(mPaymentBackend); + + mController.onStart(); + + verify(mPaymentBackend).registerCallback(mController); + } + + @Test + public void onStop_shouldUnregisterCallback() { + mController.setPaymentBackend(mPaymentBackend); + mController.onStart(); + + mController.onStop(); + + verify(mPaymentBackend).unregisterCallback(mController); + } + + @Test + public void displayPreference_shouldInitialize() { + mController.setPaymentBackend(mPaymentBackend); + + mController.displayPreference(mScreen); + + verify(mPreference).initialize(mController); + } + + @Test + public void onPaymentAppsChanged_shouldRefreshSummary() { + mController.setPaymentBackend(mPaymentBackend); + mController.displayPreference(mScreen); + when(mPaymentBackend.getDefaultApp()).thenReturn(null); + + mController.onPaymentAppsChanged(); + + assertThat(mPreference.getSummary()) + .isEqualTo(mContext.getText(R.string.nfc_payment_default_not_set)); + + final PaymentAppInfo appInfo = new PaymentAppInfo(); + appInfo.label = "test label"; + when(mPaymentBackend.getDefaultApp()).thenReturn(appInfo); + + mController.onPaymentAppsChanged(); + + assertThat(mPreference.getSummary()).isEqualTo(appInfo.label); + } +} \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java index ac6006f2c71..9ddcc6917e6 100644 --- a/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java @@ -17,7 +17,6 @@ package com.android.settings.nfc; import static com.google.common.truth.Truth.assertThat; - import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; @@ -26,8 +25,6 @@ import android.nfc.NfcAdapter; import android.nfc.NfcManager; import android.os.UserManager; import android.provider.Settings; -import androidx.preference.SwitchPreference; -import androidx.preference.PreferenceScreen; import com.android.settings.testutils.SettingsRobolectricTestRunner; @@ -42,10 +39,13 @@ import org.robolectric.util.ReflectionHelpers; import java.util.ArrayList; import java.util.List; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + @RunWith(SettingsRobolectricTestRunner.class) public class NfcPreferenceControllerTest { - Context mContext; + @Mock private NfcAdapter mNfcAdapter; @Mock @@ -55,6 +55,7 @@ public class NfcPreferenceControllerTest { @Mock private PreferenceScreen mScreen; + private Context mContext; private SwitchPreference mNfcPreference; private NfcPreferenceController mNfcController; diff --git a/tests/robotests/src/com/android/settings/nfc/PaymentSettingsTest.java b/tests/robotests/src/com/android/settings/nfc/PaymentSettingsTest.java index 6feed46dc12..02687115493 100644 --- a/tests/robotests/src/com/android/settings/nfc/PaymentSettingsTest.java +++ b/tests/robotests/src/com/android/settings/nfc/PaymentSettingsTest.java @@ -18,6 +18,7 @@ package com.android.settings.nfc; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; @@ -30,42 +31,66 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; +import java.util.ArrayList; import java.util.List; @RunWith(SettingsRobolectricTestRunner.class) +@Config(shadows = PaymentSettingsTest.ShadowPaymentBackend.class) public class PaymentSettingsTest { - @Mock - Context mContext; + static final String PAYMENT_KEY = "nfc_payment"; + static final String FOREGROUND_KEY = "nfc_foreground"; + + private Context mContext; @Mock private PackageManager mManager; - private PaymentSettings mFragment; - @Before public void setUp() { MockitoAnnotations.initMocks(this); - mFragment = new PaymentSettings(); + mContext = spy(RuntimeEnvironment.application); when(mContext.getPackageManager()).thenReturn(mManager); } @Test - public void testNonIndexableKey_NoNFC_KeyAdded() { + public void getNonIndexableKey_NoNFC_AllKeysAdded() { when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(false); final List niks = - PaymentSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); - assertThat(niks).contains(PaymentSettings.PAYMENT_KEY); + PaymentSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + assertThat(niks).contains(PAYMENT_KEY); + assertThat(niks).contains(FOREGROUND_KEY); } @Test - public void testNonIndexableKey_NFC_NoKeyAdded() { + public void getNonIndexableKey_NFC_ForegroundKeyAdded() { when(mManager.hasSystemFeature(PackageManager.FEATURE_NFC)).thenReturn(true); final List niks = - PaymentSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); - assertThat(niks).isEmpty(); + PaymentSettings.SEARCH_INDEX_DATA_PROVIDER.getNonIndexableKeys(mContext); + + assertThat(niks).contains(FOREGROUND_KEY); + } + + @Implements(PaymentBackend.class) + public static class ShadowPaymentBackend { + private ArrayList mAppInfos; + + public void __constructor__(Context context) { + mAppInfos = new ArrayList<>(); + mAppInfos.add(new PaymentBackend.PaymentAppInfo()); + } + + @Implementation + public List getPaymentAppInfos() { + return mAppInfos; + } } } \ No newline at end of file