Loading src/com/android/settings/bluetooth/BluetoothAutoOnPreferenceController.java +61 −55 Original line number Diff line number Diff line Loading @@ -16,11 +16,8 @@ package com.android.settings.bluetooth; import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.database.ContentObserver; import android.os.Handler; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import androidx.annotation.NonNull; Loading @@ -30,27 +27,33 @@ import androidx.preference.PreferenceScreen; import androidx.preference.TwoStatePreference; import com.android.settings.core.TogglePreferenceController; import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.flags.Flags; import com.android.settingslib.utils.ThreadUtils; public class BluetoothAutoOnPreferenceController extends TogglePreferenceController implements LifecycleObserver, OnStart, OnStop { private static final String TAG = "BluetoothAutoOnPreferenceController"; implements BluetoothCallback, LifecycleObserver, OnStart, OnStop { private static final String TAG = "BluetoothAutoOnPrefCtlr"; @VisibleForTesting static final String PREF_KEY = "bluetooth_auto_on_settings_toggle"; static final String SETTING_NAME = "bluetooth_automatic_turn_on"; static final int UNSET = -1; @VisibleForTesting static final int ENABLED = 1; @VisibleForTesting static final int DISABLED = 0; private final ContentObserver mContentObserver = new ContentObserver(new Handler(/* async= */ true)) { @VisibleForTesting BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); private final LocalBluetoothManager mLocalBluetoothManager = Utils.getLocalBtManager(mContext); private boolean mAutoOnValue = false; @Nullable private TwoStatePreference mPreference; public BluetoothAutoOnPreferenceController( @NonNull Context context, @NonNull String preferenceKey) { super(context, preferenceKey); } @Override public void onChange(boolean selfChange) { public void onAutoOnStateChanged(int state) { var unused = ThreadUtils.postOnBackgroundThread( () -> { Log.i(TAG, "onAutoOnStateChanged() state: " + state); updateValue(); mContext.getMainExecutor() .execute( Loading @@ -61,36 +64,39 @@ public class BluetoothAutoOnPreferenceController extends TogglePreferenceControl }); }); } }; private int mAutoOnValue = UNSET; @Nullable private TwoStatePreference mPreference; public BluetoothAutoOnPreferenceController( @NonNull Context context, @NonNull String preferenceKey) { super(context, preferenceKey); } @Override public void onStart() { mContext.getContentResolver() .registerContentObserver( Settings.Secure.getUriFor(SETTING_NAME), /* notifyForDescendants= */ false, mContentObserver); if (mLocalBluetoothManager == null) { return; } mLocalBluetoothManager.getEventManager().registerCallback(this); } @Override public void onStop() { mContext.getContentResolver().unregisterContentObserver(mContentObserver); if (mLocalBluetoothManager == null) { return; } mLocalBluetoothManager.getEventManager().unregisterCallback(this); } @Override public int getAvailabilityStatus() { if (!Flags.bluetoothQsTileDialogAutoOnToggle()) { if (mBluetoothAdapter == null) { return UNSUPPORTED_ON_DEVICE; } try { boolean isSupported = mBluetoothAdapter.isAutoOnSupported(); Log.i(TAG, "getAvailabilityStatus() isSupported: " + isSupported); if (isSupported) { var unused = ThreadUtils.postOnBackgroundThread(this::updateValue); } return isSupported ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } catch (Exception e) { // Server could throw TimeoutException, InterruptedException or ExecutionException return UNSUPPORTED_ON_DEVICE; } updateValue(); return mAutoOnValue != UNSET ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override Loading @@ -106,26 +112,20 @@ public class BluetoothAutoOnPreferenceController extends TogglePreferenceControl @Override public boolean isChecked() { return mAutoOnValue == ENABLED; return mAutoOnValue; } @Override public boolean setChecked(boolean isChecked) { if (getAvailabilityStatus() != AVAILABLE) { Log.w(TAG, "Trying to set toggle value while feature not available."); return false; } var unused = ThreadUtils.postOnBackgroundThread( () -> { boolean updated = Settings.Secure.putIntForUser( mContext.getContentResolver(), SETTING_NAME, isChecked ? ENABLED : DISABLED, UserHandle.myUserId()); if (updated) { updateValue(); try { mBluetoothAdapter.setAutoOnEnabled(isChecked); } catch (Exception e) { // Server could throw IllegalStateException, TimeoutException, // InterruptedException or ExecutionException Log.e(TAG, "Error calling setAutoOnEnabled()", e); } }); return true; Loading @@ -137,8 +137,14 @@ public class BluetoothAutoOnPreferenceController extends TogglePreferenceControl } private void updateValue() { mAutoOnValue = Settings.Secure.getIntForUser( mContext.getContentResolver(), SETTING_NAME, UNSET, UserHandle.myUserId()); if (mBluetoothAdapter == null) { return; } try { mAutoOnValue = mBluetoothAdapter.isAutoOnEnabled(); } catch (Exception e) { // Server could throw TimeoutException, InterruptedException or ExecutionException Log.e(TAG, "Error calling isAutoOnEnabled()", e); } } } src/com/android/settings/bluetooth/BluetoothSwitchPreferenceController.java +13 −10 Original line number Diff line number Diff line Loading @@ -15,13 +15,10 @@ */ package com.android.settings.bluetooth; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.SETTING_NAME; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.UNSET; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.view.View; import androidx.annotation.VisibleForTesting; Loading @@ -34,7 +31,6 @@ import com.android.settings.widget.SwitchWidgetController; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.flags.Flags; import com.android.settingslib.widget.FooterPreference; /** Loading @@ -47,11 +43,13 @@ public class BluetoothSwitchPreferenceController OnStop, SwitchWidgetController.OnSwitchChangeListener, View.OnClickListener { private static final String TAG = "BluetoothSwitchPrefCtrl"; private BluetoothEnabler mBluetoothEnabler; private RestrictionUtils mRestrictionUtils; private SwitchWidgetController mSwitch; private Context mContext; private BluetoothAdapter mBluetoothAdapter; private FooterPreference mFooterPreference; private boolean mIsAlwaysDiscoverable; Loading Loading @@ -87,6 +85,7 @@ public class BluetoothSwitchPreferenceController mRestrictionUtils); mBluetoothEnabler.setToggleCallback(this); mAlwaysDiscoverable = new AlwaysDiscoverable(context); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } @Override Loading Loading @@ -157,11 +156,15 @@ public class BluetoothSwitchPreferenceController } private boolean isAutoOnFeatureAvailable() { if (!Flags.bluetoothQsTileDialogAutoOnToggle()) { if (mBluetoothAdapter == null) { return false; } try { return mBluetoothAdapter.isAutoOnSupported(); } catch (Exception e) { // Server could throw TimeoutException, InterruptedException or ExecutionException Log.e(TAG, "Error calling isAutoOnFeatureAvailable()", e); return false; } return Settings.Secure.getIntForUser( mContext.getContentResolver(), SETTING_NAME, UNSET, UserHandle.myUserId()) != UNSET; } } tests/robotests/src/com/android/settings/bluetooth/BluetoothAutoOnPreferenceControllerTest.java +9 −29 Original line number Diff line number Diff line Loading @@ -16,82 +16,62 @@ package com.android.settings.bluetooth; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.DISABLED; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.ENABLED; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.PREF_KEY; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.SETTING_NAME; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.UNSET; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.android.settingslib.flags.Flags.FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import android.bluetooth.BluetoothAdapter; import android.content.ContentResolver; import android.content.Context; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import androidx.test.core.app.ApplicationProvider; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class BluetoothAutoOnPreferenceControllerTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private Context mContext; private ContentResolver mContentResolver; private BluetoothAutoOnPreferenceController mController; private BluetoothAdapter mBluetoothAdapter; @Before public void setUp() { mSetFlagsRule.enableFlags(FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE); mContext = spy(ApplicationProvider.getApplicationContext()); mContentResolver = mContext.getContentResolver(); mController = new BluetoothAutoOnPreferenceController(mContext, PREF_KEY); mBluetoothAdapter = spy(BluetoothAdapter.getDefaultAdapter()); mController.mBluetoothAdapter = mBluetoothAdapter; } @Test public void getAvailability_valueUnset_returnUnsupported() { Settings.Secure.putInt(mContentResolver, SETTING_NAME, UNSET); doReturn(false).when(mBluetoothAdapter).isAutoOnSupported(); assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } @Test public void getAvailability_valueSet_returnAvailable() { Settings.Secure.putInt(mContentResolver, SETTING_NAME, DISABLED); doReturn(true).when(mBluetoothAdapter).isAutoOnSupported(); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @Test public void isChecked_valueEnabled_returnTrue() { Settings.Secure.putInt(mContentResolver, SETTING_NAME, ENABLED); doReturn(true).when(mBluetoothAdapter).isAutoOnSupported(); doReturn(true).when(mBluetoothAdapter).isAutoOnEnabled(); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); assertThat(mController.isChecked()).isEqualTo(true); } @Test public void setChecked_returnTrue() { Settings.Secure.putInt(mContentResolver, SETTING_NAME, DISABLED); mController.setChecked(true); assertThat(mController.isChecked()).isEqualTo(true); } @Test public void setChecked_returnFalse() { Settings.Secure.putInt(mContentResolver, SETTING_NAME, ENABLED); mController.setChecked(false); assertThat(mController.isChecked()).isEqualTo(false); } } Loading
src/com/android/settings/bluetooth/BluetoothAutoOnPreferenceController.java +61 −55 Original line number Diff line number Diff line Loading @@ -16,11 +16,8 @@ package com.android.settings.bluetooth; import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.database.ContentObserver; import android.os.Handler; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import androidx.annotation.NonNull; Loading @@ -30,27 +27,33 @@ import androidx.preference.PreferenceScreen; import androidx.preference.TwoStatePreference; import com.android.settings.core.TogglePreferenceController; import com.android.settingslib.bluetooth.BluetoothCallback; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.flags.Flags; import com.android.settingslib.utils.ThreadUtils; public class BluetoothAutoOnPreferenceController extends TogglePreferenceController implements LifecycleObserver, OnStart, OnStop { private static final String TAG = "BluetoothAutoOnPreferenceController"; implements BluetoothCallback, LifecycleObserver, OnStart, OnStop { private static final String TAG = "BluetoothAutoOnPrefCtlr"; @VisibleForTesting static final String PREF_KEY = "bluetooth_auto_on_settings_toggle"; static final String SETTING_NAME = "bluetooth_automatic_turn_on"; static final int UNSET = -1; @VisibleForTesting static final int ENABLED = 1; @VisibleForTesting static final int DISABLED = 0; private final ContentObserver mContentObserver = new ContentObserver(new Handler(/* async= */ true)) { @VisibleForTesting BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); private final LocalBluetoothManager mLocalBluetoothManager = Utils.getLocalBtManager(mContext); private boolean mAutoOnValue = false; @Nullable private TwoStatePreference mPreference; public BluetoothAutoOnPreferenceController( @NonNull Context context, @NonNull String preferenceKey) { super(context, preferenceKey); } @Override public void onChange(boolean selfChange) { public void onAutoOnStateChanged(int state) { var unused = ThreadUtils.postOnBackgroundThread( () -> { Log.i(TAG, "onAutoOnStateChanged() state: " + state); updateValue(); mContext.getMainExecutor() .execute( Loading @@ -61,36 +64,39 @@ public class BluetoothAutoOnPreferenceController extends TogglePreferenceControl }); }); } }; private int mAutoOnValue = UNSET; @Nullable private TwoStatePreference mPreference; public BluetoothAutoOnPreferenceController( @NonNull Context context, @NonNull String preferenceKey) { super(context, preferenceKey); } @Override public void onStart() { mContext.getContentResolver() .registerContentObserver( Settings.Secure.getUriFor(SETTING_NAME), /* notifyForDescendants= */ false, mContentObserver); if (mLocalBluetoothManager == null) { return; } mLocalBluetoothManager.getEventManager().registerCallback(this); } @Override public void onStop() { mContext.getContentResolver().unregisterContentObserver(mContentObserver); if (mLocalBluetoothManager == null) { return; } mLocalBluetoothManager.getEventManager().unregisterCallback(this); } @Override public int getAvailabilityStatus() { if (!Flags.bluetoothQsTileDialogAutoOnToggle()) { if (mBluetoothAdapter == null) { return UNSUPPORTED_ON_DEVICE; } try { boolean isSupported = mBluetoothAdapter.isAutoOnSupported(); Log.i(TAG, "getAvailabilityStatus() isSupported: " + isSupported); if (isSupported) { var unused = ThreadUtils.postOnBackgroundThread(this::updateValue); } return isSupported ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } catch (Exception e) { // Server could throw TimeoutException, InterruptedException or ExecutionException return UNSUPPORTED_ON_DEVICE; } updateValue(); return mAutoOnValue != UNSET ? AVAILABLE : UNSUPPORTED_ON_DEVICE; } @Override Loading @@ -106,26 +112,20 @@ public class BluetoothAutoOnPreferenceController extends TogglePreferenceControl @Override public boolean isChecked() { return mAutoOnValue == ENABLED; return mAutoOnValue; } @Override public boolean setChecked(boolean isChecked) { if (getAvailabilityStatus() != AVAILABLE) { Log.w(TAG, "Trying to set toggle value while feature not available."); return false; } var unused = ThreadUtils.postOnBackgroundThread( () -> { boolean updated = Settings.Secure.putIntForUser( mContext.getContentResolver(), SETTING_NAME, isChecked ? ENABLED : DISABLED, UserHandle.myUserId()); if (updated) { updateValue(); try { mBluetoothAdapter.setAutoOnEnabled(isChecked); } catch (Exception e) { // Server could throw IllegalStateException, TimeoutException, // InterruptedException or ExecutionException Log.e(TAG, "Error calling setAutoOnEnabled()", e); } }); return true; Loading @@ -137,8 +137,14 @@ public class BluetoothAutoOnPreferenceController extends TogglePreferenceControl } private void updateValue() { mAutoOnValue = Settings.Secure.getIntForUser( mContext.getContentResolver(), SETTING_NAME, UNSET, UserHandle.myUserId()); if (mBluetoothAdapter == null) { return; } try { mAutoOnValue = mBluetoothAdapter.isAutoOnEnabled(); } catch (Exception e) { // Server could throw TimeoutException, InterruptedException or ExecutionException Log.e(TAG, "Error calling isAutoOnEnabled()", e); } } }
src/com/android/settings/bluetooth/BluetoothSwitchPreferenceController.java +13 −10 Original line number Diff line number Diff line Loading @@ -15,13 +15,10 @@ */ package com.android.settings.bluetooth; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.SETTING_NAME; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.UNSET; import android.app.settings.SettingsEnums; import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.os.UserHandle; import android.provider.Settings; import android.util.Log; import android.view.View; import androidx.annotation.VisibleForTesting; Loading @@ -34,7 +31,6 @@ import com.android.settings.widget.SwitchWidgetController; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.OnStart; import com.android.settingslib.core.lifecycle.events.OnStop; import com.android.settingslib.flags.Flags; import com.android.settingslib.widget.FooterPreference; /** Loading @@ -47,11 +43,13 @@ public class BluetoothSwitchPreferenceController OnStop, SwitchWidgetController.OnSwitchChangeListener, View.OnClickListener { private static final String TAG = "BluetoothSwitchPrefCtrl"; private BluetoothEnabler mBluetoothEnabler; private RestrictionUtils mRestrictionUtils; private SwitchWidgetController mSwitch; private Context mContext; private BluetoothAdapter mBluetoothAdapter; private FooterPreference mFooterPreference; private boolean mIsAlwaysDiscoverable; Loading Loading @@ -87,6 +85,7 @@ public class BluetoothSwitchPreferenceController mRestrictionUtils); mBluetoothEnabler.setToggleCallback(this); mAlwaysDiscoverable = new AlwaysDiscoverable(context); mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); } @Override Loading Loading @@ -157,11 +156,15 @@ public class BluetoothSwitchPreferenceController } private boolean isAutoOnFeatureAvailable() { if (!Flags.bluetoothQsTileDialogAutoOnToggle()) { if (mBluetoothAdapter == null) { return false; } try { return mBluetoothAdapter.isAutoOnSupported(); } catch (Exception e) { // Server could throw TimeoutException, InterruptedException or ExecutionException Log.e(TAG, "Error calling isAutoOnFeatureAvailable()", e); return false; } return Settings.Secure.getIntForUser( mContext.getContentResolver(), SETTING_NAME, UNSET, UserHandle.myUserId()) != UNSET; } }
tests/robotests/src/com/android/settings/bluetooth/BluetoothAutoOnPreferenceControllerTest.java +9 −29 Original line number Diff line number Diff line Loading @@ -16,82 +16,62 @@ package com.android.settings.bluetooth; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.DISABLED; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.ENABLED; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.PREF_KEY; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.SETTING_NAME; import static com.android.settings.bluetooth.BluetoothAutoOnPreferenceController.UNSET; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.android.settingslib.flags.Flags.FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import android.bluetooth.BluetoothAdapter; import android.content.ContentResolver; import android.content.Context; import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; import androidx.test.core.app.ApplicationProvider; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @RunWith(RobolectricTestRunner.class) public class BluetoothAutoOnPreferenceControllerTest { @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); private Context mContext; private ContentResolver mContentResolver; private BluetoothAutoOnPreferenceController mController; private BluetoothAdapter mBluetoothAdapter; @Before public void setUp() { mSetFlagsRule.enableFlags(FLAG_BLUETOOTH_QS_TILE_DIALOG_AUTO_ON_TOGGLE); mContext = spy(ApplicationProvider.getApplicationContext()); mContentResolver = mContext.getContentResolver(); mController = new BluetoothAutoOnPreferenceController(mContext, PREF_KEY); mBluetoothAdapter = spy(BluetoothAdapter.getDefaultAdapter()); mController.mBluetoothAdapter = mBluetoothAdapter; } @Test public void getAvailability_valueUnset_returnUnsupported() { Settings.Secure.putInt(mContentResolver, SETTING_NAME, UNSET); doReturn(false).when(mBluetoothAdapter).isAutoOnSupported(); assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } @Test public void getAvailability_valueSet_returnAvailable() { Settings.Secure.putInt(mContentResolver, SETTING_NAME, DISABLED); doReturn(true).when(mBluetoothAdapter).isAutoOnSupported(); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); } @Test public void isChecked_valueEnabled_returnTrue() { Settings.Secure.putInt(mContentResolver, SETTING_NAME, ENABLED); doReturn(true).when(mBluetoothAdapter).isAutoOnSupported(); doReturn(true).when(mBluetoothAdapter).isAutoOnEnabled(); assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); assertThat(mController.isChecked()).isEqualTo(true); } @Test public void setChecked_returnTrue() { Settings.Secure.putInt(mContentResolver, SETTING_NAME, DISABLED); mController.setChecked(true); assertThat(mController.isChecked()).isEqualTo(true); } @Test public void setChecked_returnFalse() { Settings.Secure.putInt(mContentResolver, SETTING_NAME, ENABLED); mController.setChecked(false); assertThat(mController.isChecked()).isEqualTo(false); } }