| /* |
| * 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 static android.app.slice.Slice.EXTRA_TOGGLE_STATE; |
| |
| import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME; |
| |
| import android.app.PendingIntent; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.pm.PackageManager; |
| import android.content.res.Resources; |
| import android.net.Uri; |
| import android.os.PersistableBundle; |
| import android.telephony.CarrierConfigManager; |
| import android.telephony.SubscriptionManager; |
| import android.telephony.ims.ImsMmTelManager; |
| import android.util.Log; |
| |
| import androidx.annotation.VisibleForTesting; |
| import androidx.core.graphics.drawable.IconCompat; |
| import androidx.slice.Slice; |
| import androidx.slice.builders.ListBuilder; |
| import androidx.slice.builders.ListBuilder.RowBuilder; |
| import androidx.slice.builders.SliceAction; |
| |
| import com.android.settings.R; |
| import com.android.settings.Utils; |
| import com.android.settings.network.ims.VolteQueryImsState; |
| import com.android.settings.slices.CustomSliceRegistry; |
| import com.android.settings.slices.SliceBroadcastReceiver; |
| |
| /** |
| * Helper class to control slices for enhanced 4g LTE settings. |
| */ |
| public class Enhanced4gLteSliceHelper { |
| |
| private static final String TAG = "Enhanced4gLteSlice"; |
| |
| /** |
| * Action passed for changes to enhanced 4g LTE slice (toggle). |
| */ |
| public static final String ACTION_ENHANCED_4G_LTE_CHANGED = |
| "com.android.settings.mobilenetwork.action.ENHANCED_4G_LTE_CHANGED"; |
| |
| /** |
| * Action for mobile network settings activity which |
| * allows setting configuration for Enhanced 4G LTE |
| * related settings |
| */ |
| public static final String ACTION_MOBILE_NETWORK_SETTINGS_ACTIVITY = |
| "android.settings.NETWORK_OPERATOR_SETTINGS"; |
| |
| private final Context mContext; |
| |
| /** |
| * Phone package name |
| */ |
| private static final String PACKAGE_PHONE = "com.android.phone"; |
| |
| /** |
| * String resource type |
| */ |
| private static final String RESOURCE_TYPE_STRING = "string"; |
| |
| /** |
| * Enhanced 4g lte mode title variant resource name |
| */ |
| private static final String RESOURCE_ENHANCED_4G_LTE_MODE_TITLE_VARIANT = |
| "enhanced_4g_lte_mode_title_variant"; |
| |
| @VisibleForTesting |
| public Enhanced4gLteSliceHelper(Context context) { |
| mContext = context; |
| } |
| |
| /** |
| * Returns Slice object for enhanced_4g_lte settings. |
| * |
| * If enhanced 4g LTE is not supported for the current carrier, this method will return slice |
| * with not supported message. |
| * |
| * If enhanced 4g LTE is not editable for the current carrier, this method will return slice |
| * with not editable message. |
| * |
| * If enhanced 4g LTE setting can be changed, this method will return the slice to toggle |
| * enhanced 4g LTE option with ACTION_ENHANCED_4G_LTE_CHANGED as endItem. |
| */ |
| public Slice createEnhanced4gLteSlice(Uri sliceUri) { |
| final int subId = getDefaultVoiceSubId(); |
| |
| if (!SubscriptionManager.isValidSubscriptionId(subId)) { |
| Log.d(TAG, "Invalid subscription Id"); |
| return null; |
| } |
| |
| if (isCarrierConfigManagerKeyEnabled( |
| CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL, subId, false) |
| || !isCarrierConfigManagerKeyEnabled( |
| CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, subId, |
| true)) { |
| Log.d(TAG, "Setting is either hidden or not editable"); |
| return null; |
| } |
| |
| final VolteQueryImsState queryState = queryImsState(subId); |
| if (!queryState.isVoLteProvisioned()) { |
| Log.d(TAG, "Setting is either not provisioned or not enabled by Platform"); |
| return null; |
| } |
| |
| try { |
| return getEnhanced4gLteSlice(sliceUri, |
| queryState.isEnabledByUser(), subId); |
| } catch (IllegalArgumentException e) { |
| Log.e(TAG, "Unable to read the current Enhanced 4g LTE status", e); |
| return null; |
| } |
| } |
| |
| /** |
| * Builds a toggle slice where the intent takes you to the Enhanced 4G LTE page and the toggle |
| * enables/disables Enhanced 4G LTE mode setting. |
| */ |
| private Slice getEnhanced4gLteSlice(Uri sliceUri, boolean isEnhanced4gLteEnabled, int subId) { |
| final IconCompat icon = IconCompat.createWithResource(mContext, |
| R.drawable.ic_launcher_settings); |
| |
| return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY) |
| .setAccentColor(Utils.getColorAccentDefaultColor(mContext)) |
| .addRow(new RowBuilder() |
| .setTitle(getEnhanced4glteModeTitle(subId)) |
| .addEndItem( |
| SliceAction.createToggle( |
| getBroadcastIntent(ACTION_ENHANCED_4G_LTE_CHANGED), |
| null /* actionTitle */, isEnhanced4gLteEnabled)) |
| .setPrimaryAction( |
| SliceAction.createDeeplink( |
| getActivityIntent(ACTION_MOBILE_NETWORK_SETTINGS_ACTIVITY), |
| icon, |
| ListBuilder.ICON_IMAGE, |
| getEnhanced4glteModeTitle(subId)))) |
| .build(); |
| } |
| |
| /** |
| * Handles Enhanced 4G LTE mode setting change from Enhanced 4G LTE slice and posts |
| * notification. Should be called when intent action is ACTION_ENHANCED_4G_LTE_CHANGED |
| * |
| * @param intent action performed |
| */ |
| public void handleEnhanced4gLteChanged(Intent intent) { |
| // skip checking when no toggle state update contained within Intent |
| final boolean newValue = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, false); |
| if (newValue != intent.getBooleanExtra(EXTRA_TOGGLE_STATE, true)) { |
| notifyEnhanced4gLteUpdate(); |
| return; |
| } |
| |
| final int subId = getDefaultVoiceSubId(); |
| if (!SubscriptionManager.isValidSubscriptionId(subId)) { |
| notifyEnhanced4gLteUpdate(); |
| return; |
| } |
| |
| final VolteQueryImsState queryState = queryImsState(subId); |
| final boolean currentValue = queryState.isEnabledByUser() |
| && queryState.isAllowUserControl(); |
| if (newValue == currentValue) { |
| notifyEnhanced4gLteUpdate(); |
| return; |
| } |
| |
| // isVoLteProvisioned() is the last item to check since it might block the main thread |
| if (queryState.isVoLteProvisioned()) { |
| setEnhanced4gLteModeSetting(subId, newValue); |
| } |
| notifyEnhanced4gLteUpdate(); |
| } |
| |
| private void notifyEnhanced4gLteUpdate() { |
| // notify change in slice in any case to get re-queried. This would result in displaying |
| // appropriate message with the updated setting. |
| mContext.getContentResolver().notifyChange(CustomSliceRegistry.ENHANCED_4G_SLICE_URI, null); |
| } |
| |
| @VisibleForTesting |
| void setEnhanced4gLteModeSetting(int subId, boolean isEnabled) { |
| if (!SubscriptionManager.isValidSubscriptionId(subId)) { |
| return; |
| } |
| final ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(subId); |
| if (imsMmTelManager == null) { |
| return; |
| } |
| try { |
| imsMmTelManager.setAdvancedCallingSettingEnabled(isEnabled); |
| } catch (IllegalArgumentException exception) { |
| Log.w(TAG, "Unable to change the Enhanced 4g LTE to " + isEnabled + ". subId=" + subId, |
| exception); |
| } |
| } |
| |
| private CharSequence getEnhanced4glteModeTitle(int subId) { |
| CharSequence ret = mContext.getText(R.string.enhanced_4g_lte_mode_title); |
| try { |
| if (isCarrierConfigManagerKeyEnabled( |
| CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_BOOL, |
| subId, |
| false)) { |
| final PackageManager manager = mContext.getPackageManager(); |
| final Resources resources = manager.getResourcesForApplication( |
| PACKAGE_PHONE); |
| final int resId = resources.getIdentifier( |
| RESOURCE_ENHANCED_4G_LTE_MODE_TITLE_VARIANT, |
| RESOURCE_TYPE_STRING, PACKAGE_PHONE); |
| ret = resources.getText(resId); |
| } |
| } catch (PackageManager.NameNotFoundException e) { |
| Log.e(TAG, "package name not found"); |
| } |
| return ret; |
| } |
| |
| /** |
| * Returns {@code true} when the key is enabled for the carrier, and {@code false} otherwise. |
| */ |
| private boolean isCarrierConfigManagerKeyEnabled(String key, |
| int subId, boolean defaultValue) { |
| final CarrierConfigManager configManager = getCarrierConfigManager(); |
| boolean ret = defaultValue; |
| if (configManager != null) { |
| final PersistableBundle bundle = configManager.getConfigForSubId(subId); |
| if (bundle != null) { |
| ret = bundle.getBoolean(key, defaultValue); |
| } |
| } |
| return ret; |
| } |
| |
| protected CarrierConfigManager getCarrierConfigManager() { |
| return mContext.getSystemService(CarrierConfigManager.class); |
| } |
| |
| private PendingIntent getBroadcastIntent(String action) { |
| final Intent intent = new Intent(action); |
| intent.setClass(mContext, SliceBroadcastReceiver.class); |
| return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent, |
| PendingIntent.FLAG_CANCEL_CURRENT); |
| } |
| |
| /** |
| * Returns the current default voice subId obtained from SubscriptionManager |
| */ |
| protected int getDefaultVoiceSubId() { |
| return SubscriptionManager.getDefaultVoiceSubscriptionId(); |
| } |
| |
| /** |
| * Returns PendingIntent to start activity specified by action |
| */ |
| private PendingIntent getActivityIntent(String action) { |
| final Intent intent = new Intent(action); |
| intent.setPackage(SETTINGS_PACKAGE_NAME); |
| intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
| return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent, 0 /* flags */); |
| } |
| |
| @VisibleForTesting |
| VolteQueryImsState queryImsState(int subId) { |
| return new VolteQueryImsState(mContext, subId); |
| } |
| } |
| |