diff --git a/res/values/strings.xml b/res/values/strings.xml index eeb9d044b9b..f5b19318e04 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -3750,6 +3750,23 @@ "Can\u2019t tether or use portable hotspots while Data Saver is on" + + Hotspot only + + USB only + + Bluetooth only + + Hotspot, USB + + Hotspot, Bluetooth + + USB, Bluetooth + + Hotspot, USB, Bluetooth + + Not sharing internet with other devices + Only share internet via USB diff --git a/src/com/android/settings/network/AllInOneTetherPreferenceController.java b/src/com/android/settings/network/AllInOneTetherPreferenceController.java index b237c777310..85cfb8bc931 100644 --- a/src/com/android/settings/network/AllInOneTetherPreferenceController.java +++ b/src/com/android/settings/network/AllInOneTetherPreferenceController.java @@ -17,12 +17,16 @@ package com.android.settings.network; import static android.os.UserManager.DISALLOW_CONFIG_TETHERING; +import static com.android.settings.network.TetherEnabler.BLUETOOTH_TETHER_KEY; +import static com.android.settings.network.TetherEnabler.KEY_ENABLE_WIFI_TETHERING; +import static com.android.settings.network.TetherEnabler.USB_TETHER_KEY; import static com.android.settingslib.RestrictedLockUtilsInternal.checkIfRestrictionEnforced; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; import android.content.Context; +import android.content.SharedPreferences; import android.os.UserHandle; import android.util.FeatureFlagUtils; import android.util.Log; @@ -34,6 +38,7 @@ import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; import androidx.preference.PreferenceScreen; +import com.android.settings.R; import com.android.settings.TetherSettings; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.FeatureFlags; @@ -48,12 +53,22 @@ import java.util.concurrent.atomic.AtomicReference; * preference. It updates the preference summary text based on tethering state. */ public class AllInOneTetherPreferenceController extends BasePreferenceController implements - LifecycleObserver { + LifecycleObserver, TetherEnabler.OnTetherStateUpdateListener { private static final String TAG = "AllInOneTetherPreferenceController"; + private static final byte HOTSPOT_ONLY = 1; + private static final byte USB_ONLY = 1 << 1; + private static final byte BLUETOOTH_ONLY = 1 << 2; + private static final byte HOTSPOT_AND_USB = HOTSPOT_ONLY | USB_ONLY; + private static final byte HOTSPOT_AND_BLUETOOTH = HOTSPOT_ONLY | BLUETOOTH_ONLY; + private static final byte USB_AND_BLUETOOTH = USB_ONLY | BLUETOOTH_ONLY; + private static final byte HOTSPOT_AND_USB_AND_BLUETOOTH = + HOTSPOT_ONLY | USB_ONLY | BLUETOOTH_ONLY; + private final boolean mAdminDisallowedTetherConfig; private final AtomicReference mBluetoothPan; private final BluetoothAdapter mBluetoothAdapter; + private final SharedPreferences mTetherEnablerSharedPreferences; @VisibleForTesting final BluetoothProfile.ServiceListener mBtProfileServiceListener = new BluetoothProfile.ServiceListener() { @@ -69,6 +84,7 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController }; private MasterSwitchPreference mPreference; + private TetherEnabler mTetherEnabler; @VisibleForTesting(otherwise = VisibleForTesting.NONE) AllInOneTetherPreferenceController() { @@ -76,6 +92,7 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController mAdminDisallowedTetherConfig = false; mBluetoothPan = new AtomicReference<>(); mBluetoothAdapter = null; + mTetherEnablerSharedPreferences = null; } public AllInOneTetherPreferenceController(Context context, String key) { @@ -84,6 +101,8 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController mAdminDisallowedTetherConfig = checkIfRestrictionEnforced( context, DISALLOW_CONFIG_TETHERING, UserHandle.myUserId()) != null; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + mTetherEnablerSharedPreferences = + context.getSharedPreferences(TetherEnabler.SHARED_PREF, Context.MODE_PRIVATE); } @Override @@ -109,11 +128,38 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController @Override public CharSequence getSummary() { if (mPreference != null && mPreference.isChecked()) { - // TODO(b/149256198) update summary accordingly. - return "Tethering"; + int chosenType = 0; + chosenType |= mTetherEnablerSharedPreferences + .getBoolean(KEY_ENABLE_WIFI_TETHERING, true) ? HOTSPOT_ONLY : 0; + chosenType |= mTetherEnablerSharedPreferences.getBoolean(USB_TETHER_KEY, false) + ? USB_ONLY : 0; + chosenType |= mTetherEnablerSharedPreferences.getBoolean(BLUETOOTH_TETHER_KEY, false) + ? BLUETOOTH_ONLY : 0; + switch (chosenType) { + case HOTSPOT_ONLY: + return mContext.getString(R.string.tether_settings_summary_hotspot_only); + case USB_ONLY: + return mContext.getString(R.string.tether_settings_summary_usb_tethering_only); + case BLUETOOTH_ONLY: + return mContext.getString( + R.string.tether_settings_summary_bluetooth_tethering_only); + case HOTSPOT_AND_USB: + return mContext.getString(R.string.tether_settings_summary_hotspot_and_usb); + case HOTSPOT_AND_BLUETOOTH: + return mContext.getString( + R.string.tether_settings_summary_hotspot_and_bluetooth); + case USB_AND_BLUETOOTH: + return mContext.getString(R.string.tether_settings_summary_usb_and_bluetooth); + case HOTSPOT_AND_USB_AND_BLUETOOTH: + return mContext.getString( + R.string.tether_settings_summary_hotspot_and_usb_and_bluetooth); + default: + Log.e(TAG, "None of the tether interfaces is chosen"); + return mContext.getString(R.string.summary_placeholder); + } } - return "Not sharing internet with other devices"; + return mContext.getString(R.string.tether_settings_summary_off); } @OnLifecycleEvent(Event.ON_CREATE) @@ -125,6 +171,20 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController } } + @OnLifecycleEvent(Event.ON_RESUME) + public void onResume() { + if (mTetherEnabler != null) { + mTetherEnabler.setListener(this); + } + } + + @OnLifecycleEvent(Event.ON_PAUSE) + public void onPause() { + if (mTetherEnabler != null) { + mTetherEnabler.setListener(null); + } + } + @OnLifecycleEvent(Event.ON_DESTROY) public void onDestroy() { final BluetoothProfile profile = mBluetoothPan.getAndSet(null); @@ -133,19 +193,20 @@ public class AllInOneTetherPreferenceController extends BasePreferenceController } } - void init(Lifecycle lifecycle) { - lifecycle.addObserver(this); - } - void initEnabler(Lifecycle lifecycle) { if (mPreference != null) { - TetherEnabler tetherEnabler = new TetherEnabler( + mTetherEnabler = new TetherEnabler( mContext, new MasterSwitchController(mPreference), mBluetoothPan); if (lifecycle != null) { - lifecycle.addObserver(tetherEnabler); + lifecycle.addObserver(mTetherEnabler); } } else { Log.e(TAG, "TetherEnabler is not initialized"); } } + + @Override + public void onTetherStateUpdated(boolean isTethering) { + updateState(mPreference); + } } diff --git a/src/com/android/settings/network/NetworkDashboardFragment.java b/src/com/android/settings/network/NetworkDashboardFragment.java index b1685fd3fcb..ad3df333bfa 100644 --- a/src/com/android/settings/network/NetworkDashboardFragment.java +++ b/src/com/android/settings/network/NetworkDashboardFragment.java @@ -66,7 +66,7 @@ public class NetworkDashboardFragment extends DashboardFragment implements use(MultiNetworkHeaderController.class).init(getSettingsLifecycle()); use(AirplaneModePreferenceController.class).setFragment(this); - use(AllInOneTetherPreferenceController.class).init(getSettingsLifecycle()); + getSettingsLifecycle().addObserver(use(AllInOneTetherPreferenceController.class)); } @Override diff --git a/src/com/android/settings/network/TetherEnabler.java b/src/com/android/settings/network/TetherEnabler.java index ffb0ef25d97..e17dcd11cbb 100644 --- a/src/com/android/settings/network/TetherEnabler.java +++ b/src/com/android/settings/network/TetherEnabler.java @@ -61,6 +61,20 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe DataSaverBackend.Listener, LifecycleObserver, SharedPreferences.OnSharedPreferenceChangeListener { + private OnTetherStateUpdateListener mListener; + + /** + * Interface definition for a callback to be invoked when the tethering has been updated. + */ + public interface OnTetherStateUpdateListener { + /** + * Called when the tethering state has changed. + * + * @param isTethering The new tethering state. + */ + void onTetherStateUpdated(boolean isTethering); + } + private static final String TAG = "TetherEnabler"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -135,6 +149,10 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe mContext.unregisterReceiver(mTetherChangeReceiver); } + public void setListener(@Nullable OnTetherStateUpdateListener listener) { + mListener = listener; + } + @VisibleForTesting void updateState(@Nullable String[] tethered) { boolean isTethering = tethered == null ? isTethering() : isTethering(tethered); @@ -143,6 +161,9 @@ public class TetherEnabler implements SwitchWidgetController.OnSwitchChangeListe } setSwitchCheckedInternal(isTethering); mSwitchWidgetController.setEnabled(!mDataSaverEnabled); + if (mListener != null) { + mListener.onTetherStateUpdated(isTethering); + } } private void setSwitchCheckedInternal(boolean checked) { diff --git a/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java index 4fbc4736adc..c74e669f009 100644 --- a/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/network/AllInOneTetherPreferenceControllerTest.java @@ -26,6 +26,7 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; import android.content.Context; +import android.content.SharedPreferences; import com.android.settings.widget.MasterSwitchPreference; @@ -48,6 +49,8 @@ public class AllInOneTetherPreferenceControllerTest { private BluetoothAdapter mBluetoothAdapter; @Mock private MasterSwitchPreference mPreference; + @Mock + private SharedPreferences mSharedPreferences; private AllInOneTetherPreferenceController mController; @@ -58,10 +61,12 @@ public class AllInOneTetherPreferenceControllerTest { ReflectionHelpers.setField(mController, "mContext", mContext); ReflectionHelpers.setField(mController, "mBluetoothAdapter", mBluetoothAdapter); ReflectionHelpers.setField(mController, "mPreference", mPreference); + ReflectionHelpers + .setField(mController, "mTetherEnablerSharedPreferences", mSharedPreferences); } @Test - public void lifeCycle_onCreate_shouldInitBluetoothPan() { + public void onCreate_shouldInitBluetoothPan() { when(mBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_ON); mController.onCreate(); @@ -71,7 +76,7 @@ public class AllInOneTetherPreferenceControllerTest { } @Test - public void lifeCycle_onCreate_shouldNotInitBluetoothPanWhenBluetoothOff() { + public void onCreate_shouldNotInitBluetoothPanWhenBluetoothOff() { when(mBluetoothAdapter.getState()).thenReturn(BluetoothAdapter.STATE_OFF); mController.onCreate();