Snap for 4807121 from 8c60fc69b7 to pi-release

Change-Id: Ic7648d7b9e99e2adc9b0b33e5013e1504f590928
This commit is contained in:
android-build-team Robot
2018-05-27 07:23:47 +00:00
44 changed files with 923 additions and 335 deletions

View File

@@ -17,7 +17,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/colorSecondary"
android:background="?android:attr/colorPrimary"
android:gravity="center_vertical"
android:orientation="horizontal" >

View File

@@ -134,4 +134,9 @@
<!-- Whether or not to show the night light suggestion. -->
<bool name="config_night_light_suggestion_enabled">true</bool>
<!-- Whether or not the device is capable of multiple levels of vibration intensity.
Note that this is different from whether it can control the vibration amplitude as some
devices will be able to vary their amplitude but do not possess enough dynamic range to
have distinct intensity levels -->
<bool name="config_vibration_supports_multiple_intensities">false</bool>
</resources>

View File

@@ -32,12 +32,14 @@
android:title="@string/nfc_quick_toggle_title"
android:icon="@drawable/ic_nfc"
android:summary="@string/nfc_quick_toggle_summary"
settings:controller="com.android.settings.nfc.NfcPreferenceController"
android:order="-7"/>
<com.android.settingslib.RestrictedPreference
android:fragment="com.android.settings.nfc.AndroidBeam"
android:key="android_beam_settings"
android:title="@string/android_beam_settings_title"
settings:controller="com.android.settings.nfc.AndroidBeamPreferenceController"
android:icon="@drawable/ic_android"
android:order="-6"/>

View File

@@ -19,8 +19,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:key="my_device_info_pref_screen"
android:title="@string/about_settings"
settings:initialExpandedChildrenCount="7">
android:title="@string/about_settings">
<com.android.settings.applications.LayoutPreference
android:key="my_device_info_header"

View File

@@ -30,6 +30,7 @@
android:key="smart_battery"
android:title="@string/smart_battery_title"
android:summary="@string/smart_battery_summary"
settings:controller="com.android.settings.fuelgauge.SmartBatteryPreferenceController"
settings:allowDividerAbove="true"/>
<SwitchPreference

View File

@@ -779,17 +779,27 @@ public class AccessibilitySettings extends SettingsPreferenceFragment implements
}
private String getVibrationSummary(Context context, @VibrationIntensity int intensity) {
switch (intensity) {
case Vibrator.VIBRATION_INTENSITY_OFF:
return context.getString(R.string.accessibility_vibration_summary_off);
case Vibrator.VIBRATION_INTENSITY_LOW:
return context.getString(R.string.accessibility_vibration_summary_low);
case Vibrator.VIBRATION_INTENSITY_MEDIUM:
return context.getString(R.string.accessibility_vibration_summary_medium);
case Vibrator.VIBRATION_INTENSITY_HIGH:
return context.getString(R.string.accessibility_vibration_summary_high);
default:
return "";
final boolean supportsMultipleIntensities = context.getResources().getBoolean(
R.bool.config_vibration_supports_multiple_intensities);
if (supportsMultipleIntensities) {
switch (intensity) {
case Vibrator.VIBRATION_INTENSITY_OFF:
return context.getString(R.string.accessibility_vibration_summary_off);
case Vibrator.VIBRATION_INTENSITY_LOW:
return context.getString(R.string.accessibility_vibration_summary_low);
case Vibrator.VIBRATION_INTENSITY_MEDIUM:
return context.getString(R.string.accessibility_vibration_summary_medium);
case Vibrator.VIBRATION_INTENSITY_HIGH:
return context.getString(R.string.accessibility_vibration_summary_high);
default:
return "";
}
} else {
if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
return context.getString(R.string.switch_on_text);
} else {
return context.getString(R.string.switch_off_text);
}
}
}

View File

@@ -17,6 +17,7 @@ import android.content.Context;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.text.TextUtils;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
@@ -61,6 +62,12 @@ public class MagnificationGesturesPreferenceController extends TogglePreferenceC
return AVAILABLE;
}
@Override
public boolean isSliceable() {
return TextUtils.equals(getPreferenceKey(),
"screen_magnification_gestures_preference_screen");
}
@Override
public CharSequence getSummary() {
int resId = 0;

View File

@@ -17,6 +17,7 @@ import android.content.Context;
import android.os.Bundle;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.text.TextUtils;
import com.android.settings.R;
import com.android.settings.core.TogglePreferenceController;
@@ -68,6 +69,12 @@ public class MagnificationNavbarPreferenceController extends TogglePreferenceCon
: UNSUPPORTED_ON_DEVICE;
}
@Override
public boolean isSliceable() {
return TextUtils.equals(getPreferenceKey(),
"screen_magnification_navbar_preference_screen");
}
@Override
public CharSequence getSummary() {
int resId = 0;

View File

@@ -15,7 +15,9 @@
*/
package com.android.settings.accessibility;
import android.media.AudioAttributes;
import android.os.Vibrator;
import android.os.VibrationEffect;
import android.provider.Settings;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -43,6 +45,11 @@ public class NotificationVibrationPreferenceFragment extends VibrationPreference
return Settings.System.NOTIFICATION_VIBRATION_INTENSITY;
}
@Override
protected int getPreviewVibrationAudioAttributesUsage() {
return AudioAttributes.USAGE_NOTIFICATION;
}
@Override
protected int getDefaultVibrationIntensity() {
Vibrator vibrator = getContext().getSystemService(Vibrator.class);

View File

@@ -1,3 +1,6 @@
# Default reviewers for this and subdirectories.
pweaver@google.com
zork@google.com
zork@google.com
per-file HapticFeedbackIntensityPreferenceController.java = michaelwr@google.com
per-file *Vibration* = michaelwr@google.com

View File

@@ -16,7 +16,9 @@
package com.android.settings.accessibility;
import android.graphics.drawable.Drawable;
import android.media.AudioAttributes;
import android.os.Vibrator;
import android.os.VibrationEffect;
import android.provider.Settings;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -50,6 +52,11 @@ public class TouchVibrationPreferenceFragment extends VibrationPreferenceFragmen
return vibrator.getDefaultHapticFeedbackIntensity();
}
@Override
protected int getPreviewVibrationAudioAttributesUsage() {
return AudioAttributes.USAGE_ASSISTANCE_SONIFICATION;
}
@Override
public void onVibrationIntensitySelected(int intensity) {
// We want to keep HAPTIC_FEEDBACK_ENABLED consistent with this setting since some

View File

@@ -81,17 +81,27 @@ public abstract class VibrationIntensityPreferenceController extends BasePrefere
}
public static CharSequence getIntensityString(Context context, int intensity) {
switch (intensity) {
case Vibrator.VIBRATION_INTENSITY_OFF:
return context.getText(R.string.accessibility_vibration_intensity_off);
case Vibrator.VIBRATION_INTENSITY_LOW:
return context.getText(R.string.accessibility_vibration_intensity_low);
case Vibrator.VIBRATION_INTENSITY_MEDIUM:
return context.getText(R.string.accessibility_vibration_intensity_medium);
case Vibrator.VIBRATION_INTENSITY_HIGH:
return context.getText(R.string.accessibility_vibration_intensity_high);
default:
return "";
final boolean supportsMultipleIntensities = context.getResources().getBoolean(
R.bool.config_vibration_supports_multiple_intensities);
if (supportsMultipleIntensities) {
switch (intensity) {
case Vibrator.VIBRATION_INTENSITY_OFF:
return context.getString(R.string.accessibility_vibration_intensity_off);
case Vibrator.VIBRATION_INTENSITY_LOW:
return context.getString(R.string.accessibility_vibration_intensity_low);
case Vibrator.VIBRATION_INTENSITY_MEDIUM:
return context.getString(R.string.accessibility_vibration_intensity_medium);
case Vibrator.VIBRATION_INTENSITY_HIGH:
return context.getString(R.string.accessibility_vibration_intensity_high);
default:
return "";
}
} else {
if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
return context.getString(R.string.switch_off_text);
} else {
return context.getString(R.string.switch_on_text);
}
}
}

View File

@@ -21,8 +21,10 @@ import android.support.annotation.VisibleForTesting;
import android.content.Context;
import android.database.ContentObserver;
import android.graphics.drawable.Drawable;
import android.media.AudioAttributes;
import android.net.Uri;
import android.os.Handler;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
import android.util.ArrayMap;
@@ -53,28 +55,15 @@ public abstract class VibrationPreferenceFragment extends RadioButtonPickerFragm
final static String KEY_INTENSITY_MEDIUM = "intensity_medium";
@VisibleForTesting
final static String KEY_INTENSITY_HIGH = "intensity_high";
// KEY_INTENSITY_ON is only used when the device doesn't support multiple intensity levels.
@VisibleForTesting
final static String KEY_INTENSITY_ON = "intensity_on";
private final Map<String, VibrationIntensityCandidateInfo> mCandidates;
private final SettingsObserver mSettingsObserver;
public VibrationPreferenceFragment() {
mCandidates = new ArrayMap<>();
mCandidates.put(KEY_INTENSITY_OFF,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_OFF,
R.string.accessibility_vibration_intensity_off,
Vibrator.VIBRATION_INTENSITY_OFF));
mCandidates.put(KEY_INTENSITY_LOW,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_LOW,
R.string.accessibility_vibration_intensity_low,
Vibrator.VIBRATION_INTENSITY_LOW));
mCandidates.put(KEY_INTENSITY_MEDIUM,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_MEDIUM,
R.string.accessibility_vibration_intensity_medium,
Vibrator.VIBRATION_INTENSITY_MEDIUM));
mCandidates.put(KEY_INTENSITY_HIGH,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_HIGH,
R.string.accessibility_vibration_intensity_high,
Vibrator.VIBRATION_INTENSITY_HIGH));
mSettingsObserver = new SettingsObserver();
}
@@ -82,6 +71,39 @@ public abstract class VibrationPreferenceFragment extends RadioButtonPickerFragm
public void onAttach(Context context) {
super.onAttach(context);
mSettingsObserver.register();
if (mCandidates.isEmpty()) {
loadCandidates(context);
}
}
private void loadCandidates(Context context) {
final boolean supportsMultipleIntensities = context.getResources().getBoolean(
R.bool.config_vibration_supports_multiple_intensities);
if (supportsMultipleIntensities) {
mCandidates.put(KEY_INTENSITY_OFF,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_OFF,
R.string.accessibility_vibration_intensity_off,
Vibrator.VIBRATION_INTENSITY_OFF));
mCandidates.put(KEY_INTENSITY_LOW,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_LOW,
R.string.accessibility_vibration_intensity_low,
Vibrator.VIBRATION_INTENSITY_LOW));
mCandidates.put(KEY_INTENSITY_MEDIUM,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_MEDIUM,
R.string.accessibility_vibration_intensity_medium,
Vibrator.VIBRATION_INTENSITY_MEDIUM));
mCandidates.put(KEY_INTENSITY_HIGH,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_HIGH,
R.string.accessibility_vibration_intensity_high,
Vibrator.VIBRATION_INTENSITY_HIGH));
} else {
mCandidates.put(KEY_INTENSITY_OFF,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_OFF,
R.string.switch_off_text, Vibrator.VIBRATION_INTENSITY_OFF));
mCandidates.put(KEY_INTENSITY_ON,
new VibrationIntensityCandidateInfo(KEY_INTENSITY_ON,
R.string.switch_on_text, getDefaultVibrationIntensity()));
}
}
@Override
@@ -105,6 +127,24 @@ public abstract class VibrationPreferenceFragment extends RadioButtonPickerFragm
*/
protected void onVibrationIntensitySelected(int intensity) { }
/**
* Play a vibration effect with intensity just selected by user
*/
protected void playVibrationPreview() {
Vibrator vibrator = getContext().getSystemService(Vibrator.class);
VibrationEffect effect = VibrationEffect.get(VibrationEffect.EFFECT_CLICK);
AudioAttributes.Builder builder = new AudioAttributes.Builder();
builder.setUsage(getPreviewVibrationAudioAttributesUsage());
vibrator.vibrate(effect, builder.build());
}
/**
* Get the AudioAttributes usage for vibration preview.
*/
protected int getPreviewVibrationAudioAttributesUsage() {
return AudioAttributes.USAGE_UNKNOWN;
}
@Override
protected List<? extends CandidateInfo> getCandidates() {
List<VibrationIntensityCandidateInfo> candidates = new ArrayList<>(mCandidates.values());
@@ -118,7 +158,10 @@ public abstract class VibrationPreferenceFragment extends RadioButtonPickerFragm
final int vibrationIntensity = Settings.System.getInt(getContext().getContentResolver(),
getVibrationIntensitySetting(), getDefaultVibrationIntensity());
for (VibrationIntensityCandidateInfo candidate : mCandidates.values()) {
if (candidate.getIntensity() == vibrationIntensity) {
final boolean matchesIntensity = candidate.getIntensity() == vibrationIntensity;
final boolean matchesOn = candidate.getKey().equals(KEY_INTENSITY_ON)
&& vibrationIntensity != Vibrator.VIBRATION_INTENSITY_OFF;
if (matchesIntensity || matchesOn) {
return candidate.getKey();
}
}
@@ -189,6 +232,7 @@ public abstract class VibrationPreferenceFragment extends RadioButtonPickerFragm
@Override
public void onChange(boolean selfChange, Uri uri) {
updateCandidates();
playVibrationPreview();
}
}
}

View File

@@ -17,8 +17,6 @@ package com.android.settings.bluetooth;
import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
import static androidx.slice.builders.ListBuilder.ICON_IMAGE;
import android.annotation.ColorInt;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
@@ -28,6 +26,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.provider.SettingsSlicesContract;
import android.support.v4.graphics.drawable.IconCompat;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settings.R;
@@ -42,8 +41,6 @@ import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.SliceAction;
import android.support.v4.graphics.drawable.IconCompat;
public class BluetoothSliceBuilder {
private static final String TAG = "BluetoothSliceBuilder";
@@ -71,7 +68,8 @@ public class BluetoothSliceBuilder {
INTENT_FILTER.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
}
private BluetoothSliceBuilder() {}
private BluetoothSliceBuilder() {
}
/**
* Return a Bluetooth Slice bound to {@link #BLUETOOTH_URI}.
@@ -80,7 +78,7 @@ public class BluetoothSliceBuilder {
* Bluetooth.
*/
public static Slice getSlice(Context context) {
final boolean isBluetoothEnabled = isBluetoothEnabled(context);
final boolean isBluetoothEnabled = isBluetoothEnabled();
final CharSequence title = context.getText(R.string.bluetooth_settings);
final IconCompat icon = IconCompat.createWithResource(context,
R.drawable.ic_settings_bluetooth);
@@ -115,9 +113,8 @@ public class BluetoothSliceBuilder {
// handle it.
}
private static boolean isBluetoothEnabled(Context context) {
final LocalBluetoothAdapter adapter = LocalBluetoothManager.getInstance(context,
null /* callback */).getBluetoothAdapter();
private static boolean isBluetoothEnabled() {
final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
return adapter.isEnabled();
}

View File

@@ -50,7 +50,7 @@ public class AdvancedConnectedDeviceController extends BasePreferenceController
*/
public static int getConnectedDevicesSummaryResourceId(Context context) {
final NfcPreferenceController nfcPreferenceController =
new NfcPreferenceController(context);
new NfcPreferenceController(context, NfcPreferenceController.KEY_TOGGLE_NFC);
return getConnectedDevicesSummaryResourceId(nfcPreferenceController,
isDrivingModeAvailable(context));

View File

@@ -24,7 +24,6 @@ import com.android.settings.R;
import com.android.settings.bluetooth.BluetoothFilesPreferenceController;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.nfc.AndroidBeamPreferenceController;
import com.android.settings.nfc.NfcPreferenceController;
import com.android.settings.print.PrintSettingPreferenceController;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
@@ -70,25 +69,15 @@ public class AdvancedConnectedDeviceDashboardFragment extends DashboardFragment
Lifecycle lifecycle) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
final AndroidBeamPreferenceController beamPreferenceController =
new AndroidBeamPreferenceController(context);
controllers.add(beamPreferenceController);
controllers.add(new BluetoothFilesPreferenceController(context));
controllers.add(new BluetoothOnWhileDrivingPreferenceController(context));
final PrintSettingPreferenceController printerController =
new PrintSettingPreferenceController(context);
final NfcPreferenceController nfcPreferenceController =
new NfcPreferenceController(context);
if (lifecycle != null) {
lifecycle.addObserver(beamPreferenceController);
lifecycle.addObserver(printerController);
lifecycle.addObserver(nfcPreferenceController);
}
controllers.add(nfcPreferenceController);
controllers.add(printerController);
return controllers;

View File

@@ -246,6 +246,16 @@ public abstract class BasePreferenceController extends AbstractPreferenceControl
return false;
}
/**
* @return {@code true} if the setting update asynchronously.
* <p>
* For example, a Wifi controller would return true, because it needs to update the radio
* and wait for it to turn on.
*/
public boolean hasAsyncUpdate() {
return false;
}
/**
* Updates non-indexable keys for search provider.
*

View File

@@ -57,14 +57,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class StorageDashboardFragment extends DashboardFragment
implements
public class StorageDashboardFragment extends DashboardFragment implements
LoaderManager.LoaderCallbacks<SparseArray<StorageAsyncLoader.AppsStorageResult>> {
private static final String TAG = "StorageDashboardFrag";
private static final int STORAGE_JOB_ID = 0;
private static final int ICON_JOB_ID = 1;
private static final int VOLUME_SIZE_JOB_ID = 2;
private static final int OPTIONS_MENU_MIGRATE_DATA = 100;
private VolumeInfo mVolume;
private PrivateStorageInfo mStorageInfo;

View File

@@ -21,6 +21,7 @@ import android.content.Context;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.Preference;
import android.text.TextUtils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory;
@@ -48,6 +49,11 @@ public class SmartBatteryPreferenceController extends BasePreferenceController i
: UNSUPPORTED_ON_DEVICE;
}
@Override
public boolean isSliceable() {
return TextUtils.equals(getPreferenceKey(), "smart_battery");
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);

View File

@@ -20,7 +20,6 @@ import android.content.Context;
import android.nfc.NfcAdapter;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.v7.preference.Preference;
import com.android.settings.R;
import com.android.settingslib.RestrictedLockUtils;
@@ -36,18 +35,14 @@ public class AndroidBeamEnabler extends BaseNfcEnabler {
public AndroidBeamEnabler(Context context, RestrictedPreference preference) {
super(context);
mPreference = preference;
mBeamDisallowedBySystem = RestrictedLockUtils.hasBaseUserRestriction(context,
UserManager.DISALLOW_OUTGOING_BEAM, UserHandle.myUserId());
if (!isNfcAvailable()) {
// NFC is not supported
mPreference.setEnabled(false);
return;
}
if (mBeamDisallowedBySystem) {
mPreference.setEnabled(false);
}

View File

@@ -16,34 +16,75 @@
package com.android.settings.nfc;
import android.content.Context;
import android.nfc.NfcAdapter;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.BasePreferenceController;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
public class AndroidBeamPreferenceController extends BaseNfcPreferenceController {
import java.util.List;
public class AndroidBeamPreferenceController extends BasePreferenceController
implements LifecycleObserver, OnResume, OnPause {
public static final String KEY_ANDROID_BEAM_SETTINGS = "android_beam_settings";
private final NfcAdapter mNfcAdapter;
private AndroidBeamEnabler mAndroidBeamEnabler;
private NfcAirplaneModeObserver mAirplaneModeObserver;
public AndroidBeamPreferenceController(Context context) {
super(context);
public AndroidBeamPreferenceController(Context context, String key) {
super(context, key);
mNfcAdapter = NfcAdapter.getDefaultAdapter(context);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
if (!isAvailable()) {
mAndroidBeamEnabler = null;
return;
}
mNfcEnabler = new AndroidBeamEnabler(mContext, (RestrictedPreference) mPreference);
final RestrictedPreference restrictedPreference =
(RestrictedPreference) screen.findPreference(getPreferenceKey());
mAndroidBeamEnabler = new AndroidBeamEnabler(mContext, restrictedPreference);
// Manually set dependencies for NFC when not toggleable.
if (!NfcPreferenceController.isToggleableInAirplaneMode(mContext)) {
mAirplaneModeObserver = new NfcAirplaneModeObserver(mContext, mNfcAdapter,
(Preference) restrictedPreference);
}
}
@Override
public String getPreferenceKey() {
return KEY_ANDROID_BEAM_SETTINGS;
@AvailabilityStatus
public int getAvailabilityStatus() {
return mNfcAdapter != null
? AVAILABLE
: UNSUPPORTED_ON_DEVICE;
}
@Override
public void onResume() {
if (mAirplaneModeObserver != null) {
mAirplaneModeObserver.register();
}
if (mAndroidBeamEnabler != null) {
mAndroidBeamEnabler.resume();
}
}
@Override
public void onPause() {
if (mAirplaneModeObserver != null) {
mAirplaneModeObserver.unregister();
}
if (mAndroidBeamEnabler != null) {
mAndroidBeamEnabler.pause();
}
}
}

View File

@@ -1,147 +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 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 android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settingslib.core.AbstractPreferenceController;
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;
public abstract class BaseNfcPreferenceController extends AbstractPreferenceController
implements PreferenceControllerMixin, LifecycleObserver, OnResume, OnPause {
protected BaseNfcEnabler mNfcEnabler;
private NfcAdapter mNfcAdapter;
private int mAirplaneMode;
private AirplaneModeObserver mAirplaneModeObserver;
protected Preference mPreference;
public BaseNfcPreferenceController(Context context) {
super(context);
mNfcAdapter = NfcAdapter.getDefaultAdapter(context);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
if (!isAvailable()) {
mNfcEnabler = null;
return;
}
mPreference = screen.findPreference(getPreferenceKey());
// Manually set dependencies for NFC when not toggleable.
if (!isToggleableInAirplaneMode(mContext)) {
mAirplaneModeObserver = new AirplaneModeObserver();
updateNfcPreference();
}
}
@Override
public void updateNonIndexableKeys(List<String> keys) {
if (!isAvailable()) {
keys.add(getPreferenceKey());
}
}
@Override
public boolean isAvailable() {
return mNfcAdapter != null;
}
public abstract String getPreferenceKey();
@Override
public void onResume() {
if (mAirplaneModeObserver != null) {
mAirplaneModeObserver.register();
}
if (mNfcEnabler != null) {
mNfcEnabler.resume();
}
}
@Override
public void onPause() {
if (mAirplaneModeObserver != null) {
mAirplaneModeObserver.unregister();
}
if (mNfcEnabler != null) {
mNfcEnabler.pause();
}
}
private void updateNfcPreference() {
final int airplaneMode = Settings.Global.getInt(
mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, mAirplaneMode);
if (airplaneMode == mAirplaneMode) {
return;
}
mAirplaneMode = airplaneMode;
boolean toggleable = mAirplaneMode != 1;
if (toggleable) {
mNfcAdapter.enable();
} else {
mNfcAdapter.disable();
}
mPreference.setEnabled(toggleable);
}
public static boolean isToggleableInAirplaneMode(Context context) {
String toggleable = Settings.Global.getString(context.getContentResolver(),
Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
return toggleable != null && toggleable.contains(Settings.Global.RADIO_NFC);
}
private final class AirplaneModeObserver extends ContentObserver {
private final Uri AIRPLANE_MODE_URI =
Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
private AirplaneModeObserver() {
super(new Handler());
}
public void register() {
mContext.getContentResolver().registerContentObserver(AIRPLANE_MODE_URI, false, this);
}
public void unregister() {
mContext.getContentResolver().unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
updateNfcPreference();
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* 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.database.ContentObserver;
import android.net.Uri;
import android.nfc.NfcAdapter;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.support.annotation.VisibleForTesting;
import android.support.v7.preference.Preference;
/**
* NfcAirplaneModeObserver is a helper to manage the Nfc on/off when airplane mode status
* is changed.
*/
public class NfcAirplaneModeObserver extends ContentObserver {
private final Context mContext;
private final NfcAdapter mNfcAdapter;
private final Preference mPreference;
private int mAirplaneMode;
@VisibleForTesting
final static Uri AIRPLANE_MODE_URI =
Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON);
public NfcAirplaneModeObserver(Context context, NfcAdapter nfcAdapter, Preference preference) {
super(new Handler(Looper.getMainLooper()));
mContext = context;
mNfcAdapter = nfcAdapter;
mPreference = preference;
updateNfcPreference();
}
public void register() {
mContext.getContentResolver().registerContentObserver(AIRPLANE_MODE_URI, false, this);
}
public void unregister() {
mContext.getContentResolver().unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
updateNfcPreference();
}
private void updateNfcPreference() {
final int airplaneMode = Settings.Global.getInt(
mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, mAirplaneMode);
if (airplaneMode == mAirplaneMode) {
return;
}
mAirplaneMode = airplaneMode;
boolean toggleable = mAirplaneMode != 1;
if (toggleable) {
mNfcAdapter.enable();
} else {
mNfcAdapter.disable();
}
mPreference.setEnabled(toggleable);
}
}

View File

@@ -18,52 +18,20 @@ package com.android.settings.nfc;
import android.content.Context;
import android.nfc.NfcAdapter;
import android.support.v7.preference.Preference;
import android.support.v14.preference.SwitchPreference;
/**
* NfcEnabler is a helper to manage the Nfc on/off checkbox preference. It turns on/off Nfc
* and ensures the summary of the preference reflects the current state.
*/
public class NfcEnabler extends BaseNfcEnabler implements Preference.OnPreferenceChangeListener {
public class NfcEnabler extends BaseNfcEnabler {
private final SwitchPreference mPreference;
public NfcEnabler(Context context, SwitchPreference preference) {
super(context);
mPreference = preference;
}
public void resume() {
super.resume();
if (isNfcAvailable()) {
mPreference.setOnPreferenceChangeListener(this);
}
}
public void pause() {
super.pause();
if (isNfcAvailable()) {
mPreference.setOnPreferenceChangeListener(null);
}
}
public boolean onPreferenceChange(Preference preference, Object value) {
// Turn NFC on/off
final boolean desiredState = (Boolean) value;
mPreference.setChecked(desiredState);
mPreference.setEnabled(false);
if (desiredState) {
mNfcAdapter.enable();
} else {
mNfcAdapter.disable();
}
return false;
}
@Override
protected void handleNfcStateChanged(int newState) {
switch (newState) {

View File

@@ -16,35 +16,119 @@
package com.android.settings.nfc;
import android.content.Context;
import android.content.IntentFilter;
import android.nfc.NfcAdapter;
import android.provider.Settings;
import android.text.TextUtils;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceScreen;
import android.support.v14.preference.SwitchPreference;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.core.TogglePreferenceController;
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;
public class NfcPreferenceController extends BaseNfcPreferenceController {
public class NfcPreferenceController extends TogglePreferenceController
implements LifecycleObserver, OnResume, OnPause {
public static final String KEY_TOGGLE_NFC = "toggle_nfc";
private final NfcAdapter mNfcAdapter;
private NfcEnabler mNfcEnabler;
private NfcAirplaneModeObserver mAirplaneModeObserver;
public NfcPreferenceController(Context context) {
super(context);
public NfcPreferenceController(Context context, String key) {
super(context, key);
mNfcAdapter = NfcAdapter.getDefaultAdapter(context);
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
if (!isAvailable()) {
mNfcEnabler = null;
return;
}
mNfcEnabler = new NfcEnabler(mContext, (SwitchPreference) mPreference);
final SwitchPreference switchPreference =
(SwitchPreference) screen.findPreference(getPreferenceKey());
mNfcEnabler = new NfcEnabler(mContext, switchPreference);
// Manually set dependencies for NFC when not toggleable.
if (!isToggleableInAirplaneMode(mContext)) {
mAirplaneModeObserver = new NfcAirplaneModeObserver(mContext,
mNfcAdapter, (Preference) switchPreference);
}
}
@Override
public String getPreferenceKey() {
return KEY_TOGGLE_NFC;
public boolean isChecked() {
return mNfcAdapter.isEnabled();
}
@Override
public boolean setChecked(boolean isChecked) {
if (isChecked) {
mNfcAdapter.enable();
} else {
mNfcAdapter.disable();
}
return true;
}
@Override
@AvailabilityStatus
public int getAvailabilityStatus() {
return mNfcAdapter != null
? AVAILABLE
: UNSUPPORTED_ON_DEVICE;
}
@Override
public IntentFilter getIntentFilter() {
final IntentFilter filter = new IntentFilter();
filter.addAction(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
filter.addAction(NfcAdapter.EXTRA_ADAPTER_STATE);
return filter;
}
@Override
public boolean hasAsyncUpdate() {
return true;
}
@Override
public boolean isSliceable() {
return TextUtils.equals(getPreferenceKey(), KEY_TOGGLE_NFC);
}
@Override
public void onResume() {
if (mAirplaneModeObserver != null) {
mAirplaneModeObserver.register();
}
if (mNfcEnabler != null) {
mNfcEnabler.resume();
}
}
@Override
public void onPause() {
if (mAirplaneModeObserver != null) {
mAirplaneModeObserver.unregister();
}
if (mNfcEnabler != null) {
mNfcEnabler.pause();
}
}
public static boolean isToggleableInAirplaneMode(Context context) {
final String toggleable = Settings.Global.getString(context.getContentResolver(),
Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
return toggleable != null && toggleable.contains(Settings.Global.RADIO_NFC);
}
}

View File

@@ -18,6 +18,7 @@ package com.android.settings.notification;
import android.content.Context;
import android.media.AudioManager;
import android.text.TextUtils;
import com.android.settings.R;
@@ -36,6 +37,11 @@ public class AlarmVolumePreferenceController extends
&& !mHelper.isSingleVolume() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
}
@Override
public boolean isSliceable() {
return TextUtils.equals(getPreferenceKey(), "alarm_volume");
}
@Override
public String getPreferenceKey() {
return KEY_ALARM_VOLUME;

View File

@@ -23,23 +23,23 @@ import android.content.ContentResolver;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.StrictMode;
import android.provider.Settings;
import android.provider.SettingsSlicesContract;
import android.support.annotation.VisibleForTesting;
import android.support.v4.graphics.drawable.IconCompat;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.KeyValueListParser;
import android.util.Log;
import android.util.Pair;
import com.android.settings.location.LocationSliceBuilder;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.bluetooth.BluetoothSliceBuilder;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.location.LocationSliceBuilder;
import com.android.settings.notification.ZenModeSliceBuilder;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.wifi.WifiSliceBuilder;
import com.android.settings.wifi.calling.WifiCallingSliceHelper;
import com.android.settings.bluetooth.BluetoothSliceBuilder;
import com.android.settings.notification.ZenModeSliceBuilder;
import com.android.settingslib.SliceBroadcastRelay;
import com.android.settingslib.utils.ThreadUtils;
@@ -150,7 +150,7 @@ public class SettingsSliceProvider extends SliceProvider {
@Override
public void onSlicePinned(Uri sliceUri) {
if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) {
registerIntentToUri(WifiSliceBuilder.INTENT_FILTER , sliceUri);
registerIntentToUri(WifiSliceBuilder.INTENT_FILTER, sliceUri);
return;
} else if (ZenModeSliceBuilder.ZEN_MODE_URI.equals(sliceUri)) {
registerIntentToUri(ZenModeSliceBuilder.INTENT_FILTER, sliceUri);
@@ -176,41 +176,51 @@ public class SettingsSliceProvider extends SliceProvider {
@Override
public Slice onBindSlice(Uri sliceUri) {
final Set<String> blockedKeys = getBlockedKeys();
final String key = sliceUri.getLastPathSegment();
if (blockedKeys.contains(key)) {
Log.e(TAG, "Requested blocked slice with Uri: " + sliceUri);
return null;
}
final StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
try {
if (!ThreadUtils.isMainThread()) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.permitAll()
.build());
}
final Set<String> blockedKeys = getBlockedKeys();
final String key = sliceUri.getLastPathSegment();
if (blockedKeys.contains(key)) {
Log.e(TAG, "Requested blocked slice with Uri: " + sliceUri);
return null;
}
// If adding a new Slice, do not directly match Slice URIs.
// Use {@link SlicesDatabaseAccessor}.
if (WifiCallingSliceHelper.WIFI_CALLING_URI.equals(sliceUri)) {
return FeatureFactory.getFactory(getContext())
.getSlicesFeatureProvider()
.getNewWifiCallingSliceHelper(getContext())
.createWifiCallingSlice(sliceUri);
} else if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) {
return WifiSliceBuilder.getSlice(getContext());
} else if (ZenModeSliceBuilder.ZEN_MODE_URI.equals(sliceUri)) {
return ZenModeSliceBuilder.getSlice(getContext());
} else if (BluetoothSliceBuilder.BLUETOOTH_URI.equals(sliceUri)) {
return BluetoothSliceBuilder.getSlice(getContext());
} else if (LocationSliceBuilder.LOCATION_URI.equals(sliceUri)) {
return LocationSliceBuilder.getSlice(getContext());
}
// If adding a new Slice, do not directly match Slice URIs.
// Use {@link SlicesDatabaseAccessor}.
if (WifiCallingSliceHelper.WIFI_CALLING_URI.equals(sliceUri)) {
return FeatureFactory.getFactory(getContext())
.getSlicesFeatureProvider()
.getNewWifiCallingSliceHelper(getContext())
.createWifiCallingSlice(sliceUri);
} else if (WifiSliceBuilder.WIFI_URI.equals(sliceUri)) {
return WifiSliceBuilder.getSlice(getContext());
} else if (ZenModeSliceBuilder.ZEN_MODE_URI.equals(sliceUri)) {
return ZenModeSliceBuilder.getSlice(getContext());
} else if (BluetoothSliceBuilder.BLUETOOTH_URI.equals(sliceUri)) {
return BluetoothSliceBuilder.getSlice(getContext());
} else if (LocationSliceBuilder.LOCATION_URI.equals(sliceUri)) {
return LocationSliceBuilder.getSlice(getContext());
}
SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri);
if (cachedSliceData == null) {
loadSliceInBackground(sliceUri);
return getSliceStub(sliceUri);
}
SliceData cachedSliceData = mSliceWeakDataCache.get(sliceUri);
if (cachedSliceData == null) {
loadSliceInBackground(sliceUri);
return getSliceStub(sliceUri);
}
// Remove the SliceData from the cache after it has been used to prevent a memory-leak.
if (!mSliceDataCache.containsKey(sliceUri)) {
mSliceWeakDataCache.remove(sliceUri);
// Remove the SliceData from the cache after it has been used to prevent a memory-leak.
if (!mSliceDataCache.containsKey(sliceUri)) {
mSliceWeakDataCache.remove(sliceUri);
}
return SliceBuilderUtils.buildSlice(getContext(), cachedSliceData);
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
return SliceBuilderUtils.buildSlice(getContext(), cachedSliceData);
}
/**

View File

@@ -27,6 +27,7 @@ import static com.android.settings.wifi.WifiSliceBuilder.ACTION_WIFI_SLICE_CHANG
import android.app.slice.Slice;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@@ -106,7 +107,9 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
if (!controller.isAvailable()) {
Log.w(TAG, "Can't update " + key + " since the setting is unavailable");
updateUri(context, key, isPlatformSlice);
if (!controller.hasAsyncUpdate()) {
updateUri(context, key, isPlatformSlice);
}
return;
}
@@ -115,7 +118,9 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
final TogglePreferenceController toggleController = (TogglePreferenceController) controller;
toggleController.setChecked(isChecked);
logSliceValueChange(context, key, isChecked ? 1 : 0);
updateUri(context, key, isPlatformSlice);
if (!controller.hasAsyncUpdate()) {
updateUri(context, key, isPlatformSlice);
}
}
private void handleSliderAction(Context context, String key, int newPosition,
@@ -151,6 +156,7 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
sliderController.setSliderPosition(newPosition);
logSliceValueChange(context, key, newPosition);
updateUri(context, key, isPlatformSlice);
}
/**
@@ -173,8 +179,15 @@ public class SliceBroadcastReceiver extends BroadcastReceiver {
}
private void updateUri(Context context, String key, boolean isPlatformDefined) {
final String path = SettingsSlicesContract.PATH_SETTING_ACTION + "/" + key;
final Uri uri = SliceBuilderUtils.getUri(path, isPlatformDefined);
final String authority = isPlatformDefined
? SettingsSlicesContract.AUTHORITY
: SettingsSliceProvider.SLICE_AUTHORITY;
final Uri uri = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(authority)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(key)
.build();
context.getContentResolver().notifyChange(uri, null /* observer */);
}
}

View File

@@ -114,4 +114,19 @@ public class MagnificationGesturesPreferenceControllerTest {
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, -1))
.isEqualTo(OFF);
}
@Test
public void isSliceableCorrectKey_returnsTrue() {
final MagnificationGesturesPreferenceController controller =
new MagnificationGesturesPreferenceController(mContext,
"screen_magnification_gestures_preference_screen");
assertThat(controller.isSliceable()).isTrue();
}
@Test
public void isSliceableIncorrectKey_returnsFalse() {
final MagnificationGesturesPreferenceController controller =
new MagnificationGesturesPreferenceController(mContext, "bad_key");
assertThat(controller.isSliceable()).isFalse();
}
}

View File

@@ -158,4 +158,19 @@ public class MagnificationNavbarPreferenceControllerTest {
sIsApplicable = applicable;
}
}
@Test
public void isSliceableCorrectKey_returnsTrue() {
final MagnificationNavbarPreferenceController controller =
new MagnificationNavbarPreferenceController(mContext,
"screen_magnification_navbar_preference_screen");
assertThat(controller.isSliceable()).isTrue();
}
@Test
public void isSliceableIncorrectKey_returnsFalse() {
final MagnificationNavbarPreferenceController controller =
new MagnificationNavbarPreferenceController(mContext, "bad_key");
assertThat(controller.isSliceable()).isFalse();
}
}

View File

@@ -18,10 +18,12 @@ package com.android.settings.accessibility;
import static android.provider.Settings.System.NOTIFICATION_VIBRATION_INTENSITY;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.arch.lifecycle.LifecycleOwner;
import android.content.Context;
import android.content.res.Resources;
import android.os.Vibrator;
import android.provider.Settings;
import android.support.v7.preference.Preference;
@@ -48,6 +50,7 @@ public class NotificationVibrationIntensityPreferenceControllerTest {
private LifecycleOwner mLifecycleOwner;
private Lifecycle mLifecycle;
private Context mContext;
private Resources mResources;
private NotificationVibrationIntensityPreferenceController mController;
private Preference mPreference;
@@ -56,7 +59,11 @@ public class NotificationVibrationIntensityPreferenceControllerTest {
MockitoAnnotations.initMocks(this);
mLifecycleOwner = () -> mLifecycle;
mLifecycle = new Lifecycle(mLifecycleOwner);
mContext = RuntimeEnvironment.application;
mContext = spy(RuntimeEnvironment.application);
mResources = spy(mContext.getResources());
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getBoolean(R.bool.config_vibration_supports_multiple_intensities))
.thenReturn(true);
mController = new NotificationVibrationIntensityPreferenceController(mContext) {
@Override
protected int getDefaultIntensity() {
@@ -68,7 +75,6 @@ public class NotificationVibrationIntensityPreferenceControllerTest {
mPreference.setSummary("Test");
when(mScreen.findPreference(mController.getPreferenceKey()))
.thenReturn(mPreference);
mController.displayPreference(mScreen);
}
@Test
@@ -80,7 +86,10 @@ public class NotificationVibrationIntensityPreferenceControllerTest {
}
@Test
public void updateState_shouldRefreshSummary() {
public void updateState_withMultipleIntensitySuport_shouldRefreshSummary() {
setSupportsMultipleIntensities(true);
showPreference();
Settings.System.putInt(mContext.getContentResolver(),
NOTIFICATION_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW);
mController.updateState(mPreference);
@@ -105,4 +114,43 @@ public class NotificationVibrationIntensityPreferenceControllerTest {
assertThat(mPreference.getSummary())
.isEqualTo(mContext.getString(R.string.accessibility_vibration_intensity_off));
}
@Test
public void updateState_withoutMultipleIntensitySupport_shouldRefreshSummary() {
setSupportsMultipleIntensities(false);
showPreference();
Settings.System.putInt(mContext.getContentResolver(),
NOTIFICATION_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_LOW);
mController.updateState(mPreference);
assertThat(mPreference.getSummary())
.isEqualTo(mContext.getString(R.string.switch_on_text));
Settings.System.putInt(mContext.getContentResolver(),
NOTIFICATION_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_HIGH);
mController.updateState(mPreference);
assertThat(mPreference.getSummary())
.isEqualTo(mContext.getString(R.string.switch_on_text));
Settings.System.putInt(mContext.getContentResolver(),
NOTIFICATION_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_MEDIUM);
mController.updateState(mPreference);
assertThat(mPreference.getSummary())
.isEqualTo(mContext.getString(R.string.switch_on_text));
Settings.System.putInt(mContext.getContentResolver(),
NOTIFICATION_VIBRATION_INTENSITY, Vibrator.VIBRATION_INTENSITY_OFF);
mController.updateState(mPreference);
assertThat(mPreference.getSummary())
.isEqualTo(mContext.getString(R.string.switch_off_text));
}
private void setSupportsMultipleIntensities(boolean hasSupport) {
when(mResources.getBoolean(R.bool.config_vibration_supports_multiple_intensities))
.thenReturn(hasSupport);
}
private void showPreference() {
mController.displayPreference(mScreen);
}
}

View File

@@ -20,16 +20,19 @@ import static com.android.settings.accessibility.VibrationPreferenceFragment.KEY
import static com.android.settings.accessibility.VibrationPreferenceFragment.KEY_INTENSITY_LOW;
import static com.android.settings.accessibility.VibrationPreferenceFragment.KEY_INTENSITY_MEDIUM;
import static com.android.settings.accessibility.VibrationPreferenceFragment.KEY_INTENSITY_OFF;
import static com.android.settings.accessibility.VibrationPreferenceFragment.KEY_INTENSITY_ON;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.os.UserManager;
import android.os.Vibrator;
import android.provider.Settings;
import com.android.settings.R;
import com.android.settings.accessibility.VibrationPreferenceFragment.VibrationIntensityCandidateInfo;
import com.android.settings.testutils.FakeFeatureFactory;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -58,12 +61,11 @@ public class VibrationPreferenceFragmentTest {
INTENSITY_TO_KEY.put(Vibrator.VIBRATION_INTENSITY_HIGH, KEY_INTENSITY_HIGH);
}
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private Activity mActivity;
@Mock
private UserManager mUserManager;
private Context mContext;
private Resources mResources;
private TestVibrationPreferenceFragment mFragment;
@Before
@@ -71,16 +73,18 @@ public class VibrationPreferenceFragmentTest {
MockitoAnnotations.initMocks(this);
FakeFeatureFactory.setupForTest();
mContext = RuntimeEnvironment.application;
mContext = spy(RuntimeEnvironment.application);
mResources = spy(mContext.getResources());
when(mContext.getResources()).thenReturn(mResources);
mFragment = spy(new TestVibrationPreferenceFragment());
doReturn(mUserManager).when(mActivity).getSystemService(Context.USER_SERVICE);
doReturn(mContext).when(mFragment).getContext();
mFragment.onAttach(mActivity);
when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
}
@Test
public void changeIntensitySetting_shouldResultInCorrespondingKey() {
setSupportsMultipleIntensities(true);
mFragment.onAttach(mContext);
for (Map.Entry<Integer, String> entry : INTENSITY_TO_KEY.entrySet()) {
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.HAPTIC_FEEDBACK_INTENSITY, entry.getKey());
@@ -88,13 +92,38 @@ public class VibrationPreferenceFragmentTest {
}
}
@Test
public void changeIntensitySetting_WithoutMultipleIntensitySupport_shouldResultInOn() {
setSupportsMultipleIntensities(false);
mFragment.onAttach(mContext);
for (int intensity : INTENSITY_TO_KEY.keySet()) {
Settings.System.putInt(mContext.getContentResolver(),
Settings.System.HAPTIC_FEEDBACK_INTENSITY, intensity);
final String expectedKey = intensity == Vibrator.VIBRATION_INTENSITY_OFF
? KEY_INTENSITY_OFF
: KEY_INTENSITY_ON;
assertThat(mFragment.getDefaultKey()).isEqualTo(expectedKey);
}
}
@Test
public void initialDefaultKey_shouldBeMedium() {
setSupportsMultipleIntensities(true);
mFragment.onAttach(mContext);
assertThat(mFragment.getDefaultKey()).isEqualTo(KEY_INTENSITY_MEDIUM);
}
@Test
public void initialDefaultKey_WithoutMultipleIntensitySupport_shouldBeOn() {
setSupportsMultipleIntensities(false);
mFragment.onAttach(mContext);
assertThat(mFragment.getDefaultKey()).isEqualTo(KEY_INTENSITY_ON);
}
@Test
public void candidates_shouldBeSortedByIntensity() {
setSupportsMultipleIntensities(true);
mFragment.onAttach(mContext);
final List<? extends CandidateInfo> candidates = mFragment.getCandidates();
assertThat(candidates.size()).isEqualTo(INTENSITY_TO_KEY.size());
VibrationIntensityCandidateInfo prevCandidate =
@@ -106,6 +135,11 @@ public class VibrationPreferenceFragmentTest {
}
}
private void setSupportsMultipleIntensities(boolean hasSupport) {
when(mResources.getBoolean(R.bool.config_vibration_supports_multiple_intensities))
.thenReturn(hasSupport);
}
private class TestVibrationPreferenceFragment extends VibrationPreferenceFragment {
@Override
protected int getPreferenceScreenResId() {
@@ -129,5 +163,10 @@ public class VibrationPreferenceFragmentTest {
protected int getDefaultVibrationIntensity() {
return Vibrator.VIBRATION_INTENSITY_MEDIUM;
}
@Override
public Context getContext() {
return mContext;
}
}
}

View File

@@ -55,7 +55,8 @@ public class AdvancedConnectedDeviceControllerTest {
mContext = spy(RuntimeEnvironment.application);
mContentResolver = mContext.getContentResolver();
mNfcController = new NfcPreferenceController(mContext);
mNfcController = new NfcPreferenceController(mContext,
NfcPreferenceController.KEY_TOGGLE_NFC);
mShadowNfcAdapter = shadowOf(ShadowNfcAdapter.getNfcAdapter(mContext));
}

View File

@@ -134,6 +134,11 @@ public class BasePreferenceControllerTest {
assertThat(mPreferenceController.getSliceType()).isEqualTo(SliceData.SliceType.INTENT);
}
@Test
public void hasAsyncUpdate_shouldReturnFalse() {
assertThat(mPreferenceController.hasAsyncUpdate()).isFalse();
}
@Test
public void settingAvailable_disabledOnDisplayPreference_preferenceEnabled() {
final PreferenceScreen screen = mock(PreferenceScreen.class);

View File

@@ -115,4 +115,11 @@ public class SmartBatteryPreferenceControllerTest {
return Settings.Global.getInt(mContentResolver,
Settings.Global.ADAPTIVE_BATTERY_MANAGEMENT_ENABLED, ON);
}
@Test
public void isSliceableCorrectKey_returnsTrue() {
final SmartBatteryPreferenceController controller =
new SmartBatteryPreferenceController(mContext);
assertThat(controller.isSliceable()).isTrue();
}
}

View File

@@ -72,7 +72,8 @@ public class AndroidBeamPreferenceControllerTest {
UserManager.DISALLOW_OUTGOING_BEAM, UserHandle.myUserId())).thenReturn(false);
when(NfcAdapter.getDefaultAdapter(mContext)).thenReturn(mNfcAdapter);
mAndroidBeamController = new AndroidBeamPreferenceController(mContext);
mAndroidBeamController = new AndroidBeamPreferenceController(mContext,
AndroidBeamPreferenceController.KEY_ANDROID_BEAM_SETTINGS);
mAndroidBeamPreference = new RestrictedPreference(RuntimeEnvironment.application);
when(mScreen.findPreference(mAndroidBeamController.getPreferenceKey())).thenReturn(
mAndroidBeamPreference);

View File

@@ -0,0 +1,85 @@
/*
* 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 android.content.Context;
import android.nfc.NfcAdapter;
import android.provider.Settings;
import android.support.v7.preference.Preference;
import android.support.v14.preference.SwitchPreference;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowNfcAdapter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.shadows.ShadowApplication;
import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = {ShadowNfcAdapter.class})
public class NfcAirplaneModeObserverTest {
Context mContext;
private NfcAdapter mNfcAdapter;
private SwitchPreference mNfcPreference;
private NfcAirplaneModeObserver mNfcAirplaneModeObserver;
@Before
public void setUp() {
mContext = ShadowApplication.getInstance().getApplicationContext();
mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext);
mNfcPreference = new SwitchPreference(RuntimeEnvironment.application);
mNfcAirplaneModeObserver = new NfcAirplaneModeObserver(mContext, mNfcAdapter,
(Preference) mNfcPreference);
}
@Test
public void NfcAirplaneModeObserver_airplaneOn_shouldDisableNfc() {
ReflectionHelpers.setField(mNfcAirplaneModeObserver,
"mAirplaneMode", 0);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 1);
mNfcAirplaneModeObserver.onChange(false,
NfcAirplaneModeObserver.AIRPLANE_MODE_URI);
assertThat(mNfcAdapter.isEnabled()).isFalse();
assertThat(mNfcPreference.isEnabled()).isFalse();
}
@Test
public void NfcAirplaneModeObserver_airplaneOff_shouldEnableNfc() {
ReflectionHelpers.setField(mNfcAirplaneModeObserver,
"mAirplaneMode", 1);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0);
mNfcAirplaneModeObserver.onChange(false,
NfcAirplaneModeObserver.AIRPLANE_MODE_URI);
assertThat(mNfcAdapter.isEnabled()).isTrue();
assertThat(mNfcPreference.isEnabled()).isTrue();
}
}

View File

@@ -19,6 +19,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.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -26,8 +27,8 @@ import android.nfc.NfcAdapter;
import android.nfc.NfcManager;
import android.os.UserManager;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.PreferenceScreen;
import android.support.v14.preference.SwitchPreference;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
@@ -68,8 +69,10 @@ public class NfcPreferenceControllerTest {
when(mContext.getSystemService(Context.NFC_SERVICE)).thenReturn(mManager);
when(NfcAdapter.getDefaultAdapter(mContext)).thenReturn(mNfcAdapter);
mNfcController = new NfcPreferenceController(mContext);
mNfcController = new NfcPreferenceController(mContext,
NfcPreferenceController.KEY_TOGGLE_NFC);
mNfcPreference = new SwitchPreference(RuntimeEnvironment.application);
when(mScreen.findPreference(mNfcController.getPreferenceKey())).thenReturn(mNfcPreference);
Settings.Global.putString(mContext.getContentResolver(),
@@ -83,15 +86,17 @@ public class NfcPreferenceControllerTest {
}
@Test
public void isAvailable_hasNfc_shouldReturnTrue() {
public void getAvailabilityStatus_hasNfc_shouldReturnAvailable() {
when(mNfcAdapter.isEnabled()).thenReturn(true);
assertThat(mNfcController.isAvailable()).isTrue();
assertThat(mNfcController.getAvailabilityStatus())
.isEqualTo(NfcPreferenceController.AVAILABLE);
}
@Test
public void isAvailable_noNfcAdapter_shouldReturnFalse() {
public void getAvailabilityStatus_noNfcAdapter_shouldReturnDisabledUnsupported() {
ReflectionHelpers.setField(mNfcController, "mNfcAdapter", null);
assertThat(mNfcController.isAvailable()).isFalse();
assertThat(mNfcController.getAvailabilityStatus())
.isEqualTo(NfcPreferenceController.UNSUPPORTED_ON_DEVICE);
}
@Test
@@ -157,4 +162,46 @@ public class NfcPreferenceControllerTest {
assertThat(keys).hasSize(1);
}
@Test
public void setChecked_True_nfcShouldEnable() {
mNfcController.setChecked(true);
mNfcController.onResume();
verify(mNfcAdapter).enable();
}
@Test
public void setChecked_False_nfcShouldDisable() {
mNfcController.setChecked(false);
mNfcController.onResume();
verify(mNfcAdapter).disable();
}
@Test
public void hasAsyncUpdate_shouldReturnTrue() {
assertThat(mNfcController.hasAsyncUpdate()).isTrue();
}
@Test
public void isToggleableInAirplaneMode_containNfc_shouldReturnTrue() {
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
Settings.Global.RADIO_NFC);
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 1);
assertThat(NfcPreferenceController.isToggleableInAirplaneMode(mContext)).isTrue();
}
@Test
public void isToggleableInAirplaneMode_withoutNfc_shouldReturnFalse() {
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS,
"null");
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 1);
assertThat(NfcPreferenceController.isToggleableInAirplaneMode(mContext)).isFalse();
}
}

View File

@@ -73,4 +73,9 @@ public class AlarmVolumePreferenceControllerTest {
public void getAudioStream_shouldReturnAlarm() {
assertThat(mController.getAudioStream()).isEqualTo(AudioManager.STREAM_ALARM);
}
@Test
public void isSliceableCorrectKey_returnsTrue() {
assertThat(mController.isSliceable()).isTrue();
}
}

View File

@@ -18,9 +18,7 @@
package com.android.settings.slices;
import static android.content.ContentResolver.SCHEME_CONTENT;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -38,19 +36,24 @@ import android.os.StrictMode;
import android.provider.SettingsSlicesContract;
import android.util.ArraySet;
import com.android.settings.location.LocationSliceBuilder;
import com.android.settings.wifi.WifiSliceBuilder;
import com.android.settings.bluetooth.BluetoothSliceBuilder;
import com.android.settings.location.LocationSliceBuilder;
import com.android.settings.notification.ZenModeSliceBuilder;
import com.android.settings.testutils.DatabaseTestUtils;
import com.android.settings.testutils.FakeToggleController;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowThreadUtils;
import com.android.settings.wifi.WifiSliceBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
import java.util.Arrays;
import java.util.Collection;
@@ -66,6 +69,7 @@ import androidx.slice.Slice;
* TODO Investigate using ShadowContentResolver.registerProviderInternal(String, ContentProvider)
*/
@RunWith(SettingsRobolectricTestRunner.class)
@Config(shadows = ShadowThreadUtils.class)
public class SettingsSliceProviderTest {
private static final String KEY = "KEY";
@@ -98,6 +102,7 @@ public class SettingsSliceProviderTest {
public void setUp() {
mContext = spy(RuntimeEnvironment.application);
mProvider = spy(new SettingsSliceProvider());
ShadowStrictMode.reset();
mProvider.mSliceWeakDataCache = new HashMap<>();
mProvider.mSliceDataCache = new HashMap<>();
mProvider.mSlicesDatabaseAccessor = new SlicesDatabaseAccessor(mContext);
@@ -112,6 +117,7 @@ public class SettingsSliceProviderTest {
@After
public void cleanUp() {
ShadowThreadUtils.reset();
DatabaseTestUtils.clearDb(mContext);
}
@@ -184,7 +190,8 @@ public class SettingsSliceProviderTest {
}
@Test
public void onBindSlice_shouldNotOverrideStrictMode() {
public void onBindSlice_mainThread_shouldNotOverrideStrictMode() {
ShadowThreadUtils.setIsMainThread(true);
final StrictMode.ThreadPolicy oldThreadPolicy = StrictMode.getThreadPolicy();
SliceData data = getDummyData();
mProvider.mSliceWeakDataCache.put(data.getUri(), data);
@@ -195,6 +202,18 @@ public class SettingsSliceProviderTest {
assertThat(newThreadPolicy.toString()).isEqualTo(oldThreadPolicy.toString());
}
@Test
@Config(shadows = ShadowStrictMode.class)
public void onBindSlice_backgroundThread_shouldOverrideStrictMode() {
ShadowThreadUtils.setIsMainThread(false);
SliceData data = getDummyData();
mProvider.mSliceWeakDataCache.put(data.getUri(), data);
mProvider.onBindSlice(data.getUri());
assertThat(ShadowStrictMode.isThreadPolicyOverridden()).isTrue();
}
@Test
public void onBindSlice_requestsBlockedSlice_retunsNull() {
final String blockedKey = "blocked_key";
@@ -456,7 +475,7 @@ public class SettingsSliceProviderTest {
mDb.replaceOrThrow(SlicesDatabaseHelper.Tables.TABLE_SLICES_INDEX, null, values);
}
private SliceData getDummyData() {
private static SliceData getDummyData() {
return new SliceData.Builder()
.setKey(KEY)
.setTitle(TITLE)
@@ -468,4 +487,24 @@ public class SettingsSliceProviderTest {
.setPreferenceControllerClassName(PREF_CONTROLLER)
.build();
}
@Implements(value = StrictMode.class, inheritImplementationMethods = true)
public static class ShadowStrictMode {
private static int sSetThreadPolicyCount;
@Resetter
public static void reset() {
sSetThreadPolicyCount = 0;
}
@Implementation
public static void setThreadPolicy(final StrictMode.ThreadPolicy policy) {
sSetThreadPolicyCount++;
}
public static boolean isThreadPolicyOverridden() {
return sSetThreadPolicyCount != 0;
}
}
}

View File

@@ -23,6 +23,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -95,8 +96,16 @@ public class SliceBroadcastReceiverTest {
@Test
public void onReceive_toggleChanged() {
final String key = "key";
final Uri uri = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(key)
.build();
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
insertSpecialCase(key);
final ContentResolver resolver = mock(ContentResolver.class);
doReturn(resolver).when(mContext).getContentResolver();
// Turn on toggle setting
FakeToggleController fakeToggleController = new FakeToggleController(mContext, key);
fakeToggleController.setChecked(true);
@@ -120,14 +129,77 @@ public class SliceBroadcastReceiverTest {
assertThat(namePair.first).isEqualTo(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME);
assertThat(namePair.second).isEqualTo(fakeToggleController.getPreferenceKey());
verify(resolver).notifyChange(uri, null);
assertThat(valuePair.first)
.isEqualTo(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE);
assertThat(valuePair.second).isEqualTo(0);
}
@Test
public void toggleUpdate_synchronously_notifyChange_should_be_called() {
// Monitor the ContentResolver
final ContentResolver resolver = spy(mContext.getContentResolver());
doReturn(resolver).when(mContext).getContentResolver();
final String key = "key";
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
insertSpecialCase(key);
FakeToggleController fakeToggleController = new FakeToggleController(mContext, key);
fakeToggleController.setChecked(true);
// Set the toggle setting update synchronously.
fakeToggleController.setAsyncUpdate(false);
Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
assertThat(fakeToggleController.isChecked()).isTrue();
// Toggle setting
mReceiver.onReceive(mContext, intent);
assertThat(fakeToggleController.isChecked()).isFalse();
final Uri expectedUri = SliceBuilderUtils.getUri(
SettingsSlicesContract.PATH_SETTING_ACTION + "/" + key, false);
verify(resolver).notifyChange(eq(expectedUri), eq(null));
}
@Test
public void toggleUpdate_asynchronously_notifyChange_should_not_be_called() {
// Monitor the ContentResolver
final ContentResolver resolver = spy(mContext.getContentResolver());
doReturn(resolver).when(mContext).getContentResolver();
final String key = "key";
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
insertSpecialCase(key);
FakeToggleController fakeToggleController = new FakeToggleController(mContext, key);
fakeToggleController.setChecked(true);
// Set the toggle setting update asynchronously.
fakeToggleController.setAsyncUpdate(true);
Intent intent = new Intent(SettingsSliceProvider.ACTION_TOGGLE_CHANGED);
intent.putExtra(SettingsSliceProvider.EXTRA_SLICE_KEY, key);
assertThat(fakeToggleController.isChecked()).isTrue();
// Toggle setting
mReceiver.onReceive(mContext, intent);
verify(resolver, never()).notifyChange(null, null);
}
@Test
public void onReceive_sliderChanged() {
final String key = "key";
final Uri uri = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(key)
.build();
final ContentResolver resolver = mock(ContentResolver.class);
doReturn(resolver).when(mContext).getContentResolver();
final int position = FakeSliderController.MAX_STEPS - 1;
final int oldPosition = FakeSliderController.MAX_STEPS;
mSearchFeatureProvider.getSearchIndexableResources().getProviderValues().clear();
@@ -158,6 +230,7 @@ public class SliceBroadcastReceiverTest {
assertThat(namePair.first).isEqualTo(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME);
assertThat(namePair.second).isEqualTo(key);
verify(resolver).notifyChange(uri, null);
assertThat(valuePair.first)
.isEqualTo(MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE);
assertThat(valuePair.second).isEqualTo(position);
@@ -231,8 +304,12 @@ public class SliceBroadcastReceiverTest {
// Check the value is the same and the Uri has been notified.
assertThat(fakeToggleController.isChecked()).isTrue();
final Uri expectedUri = SliceBuilderUtils.getUri(
SettingsSlicesContract.PATH_SETTING_ACTION + "/" + key, false);
final Uri expectedUri = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(key)
.build();
verify(resolver).notifyChange(eq(expectedUri), eq(null));
}
@@ -268,8 +345,12 @@ public class SliceBroadcastReceiverTest {
// Check position is the same and the Uri has been notified.
assertThat(fakeSliderController.getSliderPosition()).isEqualTo(oldPosition);
final Uri expectedUri = SliceBuilderUtils.getUri(
SettingsSlicesContract.PATH_SETTING_ACTION + "/" + key, false);
final Uri expectedUri = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(SettingsSliceProvider.SLICE_AUTHORITY)
.appendPath(SettingsSlicesContract.PATH_SETTING_ACTION)
.appendPath(key)
.build();
verify(resolver).notifyChange(eq(expectedUri), eq(null));
}

View File

@@ -36,6 +36,8 @@ public class FakeToggleController extends TogglePreferenceController {
private final int ON = 1;
private final int OFF = 0;
private boolean mIsAsyncUpdate = false;
public FakeToggleController(Context context, String preferenceKey) {
super(context, preferenceKey);
}
@@ -67,4 +69,13 @@ public class FakeToggleController extends TogglePreferenceController {
public boolean isSliceable() {
return true;
}
@Override
public boolean hasAsyncUpdate() {
return mIsAsyncUpdate;
}
public void setAsyncUpdate(boolean isAsyncUpdate) {
mIsAsyncUpdate = isAsyncUpdate;
}
}

View File

@@ -33,6 +33,7 @@ import org.robolectric.util.ReflectionHelpers.ClassParameter;
@Implements(NfcAdapter.class)
public class ShadowNfcAdapter {
private static boolean sReaderModeEnabled;
private boolean mIsNfcEnabled = false;
@Implementation
public void enableReaderMode(Activity activity, NfcAdapter.ReaderCallback callback, int flags,
@@ -46,6 +47,23 @@ public class ShadowNfcAdapter {
NfcAdapter.class, ClassParameter.from(Context.class, context));
}
@Implementation
public boolean isEnabled() {
return mIsNfcEnabled;
}
@Implementation
public boolean enable() {
mIsNfcEnabled = true;
return true;
}
@Implementation
public boolean disable() {
mIsNfcEnabled = false;
return true;
}
public static boolean isReaderModeEnabled() {
return sReaderModeEnabled;
}

View File

@@ -20,10 +20,18 @@ import com.android.settingslib.utils.ThreadUtils;
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.Resetter;
@Implements(ThreadUtils.class)
public class ShadowThreadUtils {
private static boolean sIsMainThread = true;
@Resetter
public static void reset() {
sIsMainThread = true;
}
@Implementation
public static void postOnBackgroundThread(Runnable runnable) {
runnable.run();
@@ -33,4 +41,14 @@ public class ShadowThreadUtils {
public static void postOnMainThread(Runnable runnable) {
runnable.run();
}
@Implementation
public static boolean isMainThread() {
return sIsMainThread;
}
public static void setIsMainThread(boolean isMainThread) {
sIsMainThread = isMainThread;
}
}