diff --git a/res/values/evolution_strings.xml b/res/values/evolution_strings.xml index d00d968c24e..80f16138cfd 100644 --- a/res/values/evolution_strings.xml +++ b/res/values/evolution_strings.xml @@ -157,4 +157,8 @@ Up to %1$d devices can connect to this hotspot Up to %1$d device can connect to this hotspot + + + Smart 5G + Automatically switch between 5G and 4G to reduce battery consumption diff --git a/res/xml/mobile_network_settings.xml b/res/xml/mobile_network_settings.xml index 72d03bab62c..d40f85f50ec 100644 --- a/res/xml/mobile_network_settings.xml +++ b/res/xml/mobile_network_settings.xml @@ -295,6 +295,13 @@ android:key="choose_network_key" android:title="@string/choose_network_title" settings:controller="com.android.settings.network.telephony.gsm.OpenNetworkSelectPagePreferenceController"/> + + diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index 756206751ec..a8ed8e2f63a 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -330,6 +330,7 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme .addListener(videoCallingPreferenceController); use(ContactDiscoveryPreferenceController.class).init(getParentFragmentManager(), mSubId); use(NrAdvancedCallingPreferenceController.class).init(mSubId); + use(Smart5gPreferenceController.class).init(mSubId); use(TransferEsimPreferenceController.class).init(mSubId, mSubscriptionInfoEntity); use(ForceLteCaPreferenceController.class).init(mSubId); final ConvertToEsimPreferenceController convertToEsimPreferenceController = diff --git a/src/com/android/settings/network/telephony/Smart5gPreferenceController.java b/src/com/android/settings/network/telephony/Smart5gPreferenceController.java new file mode 100644 index 00000000000..cfff7a66bb1 --- /dev/null +++ b/src/com/android/settings/network/telephony/Smart5gPreferenceController.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2021 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.network.telephony; + +import static android.provider.Settings.System.SMART_5G; + +import android.content.Context; +import android.os.UserHandle; +import android.provider.Settings; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyManager; +import android.util.Log; + +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreferenceCompat; +import androidx.preference.TwoStatePreference; + +import com.android.settingslib.core.lifecycle.LifecycleObserver; +import com.android.settingslib.core.lifecycle.events.OnStart; +import com.android.settingslib.core.lifecycle.events.OnStop; + +/** + * Preference controller for Smart 5G + */ +public class Smart5gPreferenceController extends TelephonyTogglePreferenceController + implements LifecycleObserver, OnStart, OnStop { + + private static final String TAG = "Smart5gPreferenceController"; + + Preference mPreference; + private TelephonyManager mTelephonyManager; + private PhoneCallStateTelephonyCallback mTelephonyCallback; + private boolean mHas5gCapability = false; + private Integer mCallState = TelephonyManager.CALL_STATE_IDLE; + + public Smart5gPreferenceController(Context context, String key) { + super(context, key); + mTelephonyManager = context.getSystemService(TelephonyManager.class); + } + + /** + * Initialize this PreferenceController. + * @param subId The subscription Id. + * @return This PreferenceController. + */ + public Smart5gPreferenceController init(int subId) { + Log.d(TAG, "init: subId=" + subId); + if (mTelephonyCallback == null) { + mTelephonyCallback = new PhoneCallStateTelephonyCallback(); + } + + mSubId = subId; + + if (mTelephonyManager == null) { + mTelephonyManager = mContext.getSystemService(TelephonyManager.class); + } + if (SubscriptionManager.isValidSubscriptionId(subId)) { + mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId); + } + long supportedRadioBitmask = mTelephonyManager.getSupportedRadioAccessFamily(); + mHas5gCapability = + (supportedRadioBitmask & TelephonyManager.NETWORK_TYPE_BITMASK_NR) > 0; + + Log.d(TAG, "mHas5gCapability: " + mHas5gCapability); + return this; + } + + @Override + public int getAvailabilityStatus(int subId) { + init(subId); + return mHas5gCapability ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + } + + @Override + public void onStart() { + if (mTelephonyCallback == null) { + return; + } + mTelephonyCallback.register(mTelephonyManager); + } + + @Override + public void onStop() { + if (mTelephonyCallback == null) { + return; + } + mTelephonyCallback.unregister(); + } + + @Override + public void updateState(Preference preference) { + super.updateState(preference); + if (preference == null) { + return; + } + final TwoStatePreference switchPreference = (TwoStatePreference) preference; + switchPreference.setEnabled(isUserControlAllowed()); + } + + @Override + public boolean setChecked(boolean isChecked) { + if (!SubscriptionManager.isValidSubscriptionId(mSubId)) { + return false; + } + return Settings.System.putIntForUser(mContext.getContentResolver(), + SMART_5G + mSubId, isChecked ? 1 : 0, UserHandle.USER_CURRENT); + } + + @Override + public boolean isChecked() { + return Settings.System.getIntForUser(mContext.getContentResolver(), + SMART_5G + mSubId, 0, UserHandle.USER_CURRENT) == 1; + } + + protected boolean isCallStateIdle() { + return (mCallState != null) && (mCallState == TelephonyManager.CALL_STATE_IDLE); + } + + private boolean isUserControlAllowed() { + return isCallStateIdle(); + } + + private class PhoneCallStateTelephonyCallback extends TelephonyCallback implements + TelephonyCallback.CallStateListener { + + private TelephonyManager mLocalTelephonyManager; + + @Override + public void onCallStateChanged(int state) { + mCallState = state; + updateState(mPreference); + } + + public void register(TelephonyManager telephonyManager) { + mLocalTelephonyManager = telephonyManager; + + // assign current call state so that it helps to show correct preference state even + // before first onCallStateChanged() by initial registration. + mCallState = mLocalTelephonyManager.getCallState(); + mLocalTelephonyManager.registerTelephonyCallback( + mContext.getMainExecutor(), mTelephonyCallback); + } + + public void unregister() { + mCallState = null; + if (mLocalTelephonyManager != null) { + mLocalTelephonyManager.unregisterTelephonyCallback(this); + } + } + } +}