Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f218f762 authored by Chaohui Wang's avatar Chaohui Wang
Browse files

Create VideoCallingRepository

Also support settings search for video calling.

Fix: 233327342
Flag: EXEMPT bug fix
Test: manual - on mobile settings
Test: manual - search video calling
Test: unit test
Change-Id: Ic4a25849f77f1759fa157931d428daa9e6854ff2
parent a73545d8
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -221,10 +221,11 @@
                </intent>
            </Preference>

            <!-- Settings search is handled by WifiCallingSearchItem. -->
            <SwitchPreferenceCompat
                android:key="video_calling_key"
                android:title="@string/video_calling_settings_title"
                android:persistent="true"
                settings:searchable="false"
                settings:controller="com.android.settings.network.telephony.VideoCallingPreferenceController"/>

        </PreferenceCategory>
+4 −33
Original line number Diff line number Diff line
@@ -18,24 +18,17 @@ package com.android.settings.network.ims;

import android.content.Context;
import android.telecom.TelecomManager;
import android.telephony.AccessNetworkConstants;
import android.telephony.SubscriptionManager;
import android.telephony.ims.ImsException;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.Log;

import androidx.annotation.VisibleForTesting;

/**
 * Controller class for querying VT status
 */
public class VtQueryImsState extends ImsQueryController {
public class VtQueryImsState {

    private static final String LOG_TAG = "VtQueryImsState";

    private Context mContext;
    private int mSubId;
    private final Context mContext;
    private final int mSubId;

    /**
     * Constructor
@@ -44,9 +37,6 @@ public class VtQueryImsState extends ImsQueryController {
     * @param subId subscription's id
     */
    public VtQueryImsState(Context context, int subId) {
        super(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO,
                ImsRegistrationImplBase.REGISTRATION_TECH_LTE,
                AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
        mContext = context;
        mSubId = subId;
    }
@@ -62,24 +52,6 @@ public class VtQueryImsState extends ImsQueryController {
        return (new ImsQueryVtUserSetting(subId)).query();
    }

    /**
     * Check whether Video Call can be perform or not on this subscription
     *
     * @return true when Video Call can be performed, otherwise false
     */
    public boolean isReadyToVideoCall() {
        if (!isProvisionedOnDevice(mSubId)) {
            return false;
        }

        try {
            return isEnabledByPlatform(mSubId) && isServiceStateReady(mSubId);
        } catch (InterruptedException | IllegalArgumentException | ImsException exception) {
            Log.w(LOG_TAG, "fail to get Vt ready. subId=" + mSubId, exception);
        }
        return false;
    }

    /**
     * Get allowance status for user to alter configuration
     *
@@ -89,8 +61,7 @@ public class VtQueryImsState extends ImsQueryController {
        if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
            return false;
        }
        return ((!isTtyEnabled(mContext))
                || (isTtyOnVolteEnabled(mSubId)));
        return !isTtyEnabled(mContext) || new ImsQueryTtyOnVolteStat(mSubId).query();
    }

    @VisibleForTesting
+11 −2
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ class CarrierConfigRepository(private val context: Context) {
        private val keysToRetrieve = mutableMapOf<String, KeyType>()

        override fun getBoolean(key: String): Boolean {
            check(key.endsWith("_bool")) { "Boolean key should ends with _bool" }
            checkBooleanKey(key)
            val value = cache[key]
            return if (value == null) {
                keysToRetrieve += key to KeyType.BOOLEAN
@@ -186,9 +186,18 @@ class CarrierConfigRepository(private val context: Context) {
            ListenerRegistered.getAndSet(false)
        }

        private val BooleanKeysWhichNotFollowingsNamingConventions =
            listOf(CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS)

        private fun checkBooleanKey(key: String) {
            check(key.endsWith("_bool") || key in BooleanKeysWhichNotFollowingsNamingConventions) {
                "Boolean key should ends with _bool"
            }
        }

        @VisibleForTesting
        fun setBooleanForTest(subId: Int, key: String, value: Boolean) {
            check(key.endsWith("_bool")) { "Boolean key should ends with _bool" }
            checkBooleanKey(key)
            getPerSubCache(subId)[key] = BooleanConfigValue(value)
        }

+2 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import com.android.settings.network.telephony.DataUsagePreferenceController.Comp
import com.android.settings.network.telephony.MmsMessagePreferenceController.Companion.MmsMessageSearchItem
import com.android.settings.network.telephony.NrAdvancedCallingPreferenceController.Companion.NrAdvancedCallingSearchItem
import com.android.settings.network.telephony.RoamingPreferenceController.Companion.RoamingSearchItem
import com.android.settings.network.telephony.VideoCallingPreferenceController.Companion.VideoCallingSearchItem
import com.android.settings.network.telephony.WifiCallingPreferenceController.Companion.WifiCallingSearchItem
import com.android.settings.spa.SpaSearchLanding.BundleValue
import com.android.settings.spa.SpaSearchLanding.SpaSearchLandingFragment
@@ -122,6 +123,7 @@ class MobileNetworkSettingsSearchIndex(
                NrAdvancedCallingSearchItem(context),
                PreferredNetworkModeSearchItem(context),
                RoamingSearchItem(context),
                VideoCallingSearchItem(context),
                WifiCallingSearchItem(context),
            )
    }
+0 −234
Original line number Diff line number Diff line
/*
 * 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.network.telephony;

import android.content.Context;
import android.content.pm.PackageManager;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyCallback;
import android.telephony.TelephonyManager;
import android.telephony.ims.ImsMmTelManager;
import android.util.Log;

import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import androidx.preference.TwoStatePreference;

import com.android.internal.telephony.flags.Flags;
import com.android.settings.network.CarrierConfigCache;
import com.android.settings.network.MobileDataEnabledListener;
import com.android.settings.network.ims.VolteQueryImsState;
import com.android.settings.network.ims.VtQueryImsState;
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 "Video Calling"
 */
public class VideoCallingPreferenceController extends TelephonyTogglePreferenceController implements
        LifecycleObserver, OnStart, OnStop,
        MobileDataEnabledListener.Client,
        Enhanced4gBasePreferenceController.On4gLteUpdateListener {

    private static final String TAG = "VideoCallingPreference";

    private Preference mPreference;
    private PhoneTelephonyCallback mTelephonyCallback;
    @VisibleForTesting
    Integer mCallState;
    private MobileDataEnabledListener mDataContentObserver;
    private CallingPreferenceCategoryController mCallingPreferenceCategoryController;

    public VideoCallingPreferenceController(Context context, String key) {
        super(context, key);
        mDataContentObserver = new MobileDataEnabledListener(context, this);
        mTelephonyCallback = new PhoneTelephonyCallback();
    }

    @Override
    public int getAvailabilityStatus(int subId) {
        return SubscriptionManager.isValidSubscriptionId(subId)
                && isVideoCallEnabled(subId)
                ? AVAILABLE
                : CONDITIONALLY_UNAVAILABLE;
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mPreference = screen.findPreference(getPreferenceKey());
    }

    @Override
    public void onStart() {
        mTelephonyCallback.register(mContext, mSubId);
        mDataContentObserver.start(mSubId);
    }

    @Override
    public void onStop() {
        mTelephonyCallback.unregister();
        mDataContentObserver.stop();
    }

    @Override
    public void updateState(Preference preference) {
        super.updateState(preference);
        if ((mCallState == null) || (preference == null)) {
            Log.d(TAG, "Skip update under mCallState=" + mCallState);
            return;
        }
        final TwoStatePreference switchPreference = (TwoStatePreference) preference;
        final boolean videoCallEnabled = isVideoCallEnabled(mSubId);
        switchPreference.setVisible(videoCallEnabled);
        mCallingPreferenceCategoryController
                .updateChildVisible(getPreferenceKey(), videoCallEnabled);
        if (videoCallEnabled) {
            final boolean videoCallEditable = queryVoLteState(mSubId).isEnabledByUser()
                    && queryImsState(mSubId).isAllowUserControl();
            preference.setEnabled(videoCallEditable
                    && mCallState == TelephonyManager.CALL_STATE_IDLE);
            switchPreference.setChecked(videoCallEditable && isChecked());
        }
    }

    @Override
    public boolean setChecked(boolean isChecked) {
        if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
            return false;
        }
        final ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(mSubId);
        if (imsMmTelManager == null) {
            return false;
        }
        try {
            imsMmTelManager.setVtSettingEnabled(isChecked);
            return true;
        } catch (IllegalArgumentException exception) {
            Log.w(TAG, "Unable to set VT status " + isChecked + ". subId=" + mSubId,
                    exception);
        }
        return false;
    }

    @Override
    public boolean isChecked() {
        return queryImsState(mSubId).isEnabledByUser();
    }

    @VisibleForTesting
    protected boolean isImsSupported() {
        return mContext.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_TELEPHONY_IMS);
    }

    /**
     * Init instance of VideoCallingPreferenceController.
     */
    public VideoCallingPreferenceController init(
            int subId, CallingPreferenceCategoryController callingPreferenceCategoryController) {
        mSubId = subId;
        mCallingPreferenceCategoryController = callingPreferenceCategoryController;

        return this;
    }

    @VisibleForTesting
    boolean isVideoCallEnabled(int subId) {
        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
            return false;
        }

        final PersistableBundle carrierConfig =
                CarrierConfigCache.getInstance(mContext).getConfigForSubId(subId);
        if (carrierConfig == null) {
            return false;
        }

        if (!carrierConfig.getBoolean(
                CarrierConfigManager.KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS)
                && (!mContext.getSystemService(TelephonyManager.class)
                    .createForSubscriptionId(subId).isDataEnabled())) {
            return false;
        }

        return isImsSupported() && queryImsState(subId).isReadyToVideoCall();
    }

    @Override
    public void on4gLteUpdated() {
        updateState(mPreference);
    }

    private class PhoneTelephonyCallback extends TelephonyCallback implements
            TelephonyCallback.CallStateListener {

        private TelephonyManager mTelephonyManager;

        @Override
        public void onCallStateChanged(int state) {
            mCallState = state;
            updateState(mPreference);
        }

        public void register(Context context, int subId) {
            mTelephonyManager = context.getSystemService(TelephonyManager.class);
            if (SubscriptionManager.isValidSubscriptionId(subId)) {
                mTelephonyManager = mTelephonyManager.createForSubscriptionId(subId);
            }
            // assign current call state so that it helps to show correct preference state even
            // before first onCallStateChanged() by initial registration.
            if (Flags.enforceTelephonyFeatureMappingForPublicApis()) {
                try {
                    mCallState = mTelephonyManager.getCallState(subId);
                } catch (UnsupportedOperationException e) {
                    // Device doesn't support FEATURE_TELEPHONY_CALLING
                    mCallState = TelephonyManager.CALL_STATE_IDLE;
                }
            } else {
                mCallState = mTelephonyManager.getCallState(subId);
            }
            mTelephonyManager.registerTelephonyCallback(context.getMainExecutor(), this);
        }

        public void unregister() {
            mCallState = null;
            mTelephonyManager.unregisterTelephonyCallback(this);
        }
    }

    /**
     * Implementation of MobileDataEnabledListener.Client
     */
    public void onMobileDataEnabledChange() {
        updateState(mPreference);
    }

    @VisibleForTesting
    VtQueryImsState queryImsState(int subId) {
        return new VtQueryImsState(mContext, subId);
    }

    @VisibleForTesting
    VolteQueryImsState queryVoLteState(int subId) {
        return new VolteQueryImsState(mContext, subId);
    }
}
Loading