• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.network.telephony;
18 
19 import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;
20 
21 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;
22 
23 import android.app.PendingIntent;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.net.Uri;
27 import android.os.PersistableBundle;
28 import android.telephony.CarrierConfigManager;
29 import android.telephony.SubscriptionManager;
30 import android.telephony.ims.ImsMmTelManager;
31 import android.util.Log;
32 
33 import androidx.annotation.VisibleForTesting;
34 import androidx.core.graphics.drawable.IconCompat;
35 import androidx.slice.Slice;
36 import androidx.slice.builders.ListBuilder;
37 import androidx.slice.builders.ListBuilder.RowBuilder;
38 import androidx.slice.builders.SliceAction;
39 
40 import com.android.settings.R;
41 import com.android.settings.Utils;
42 import com.android.settings.network.ims.VolteQueryImsState;
43 import com.android.settings.slices.CustomSliceRegistry;
44 import com.android.settings.slices.SliceBroadcastReceiver;
45 
46 /**
47  * Helper class to control slices for enhanced 4g LTE settings.
48  */
49 public class Enhanced4gLteSliceHelper {
50 
51     private static final String TAG = "Enhanced4gLteSlice";
52 
53     /**
54      * Action passed for changes to enhanced 4g LTE slice (toggle).
55      */
56     public static final String ACTION_ENHANCED_4G_LTE_CHANGED =
57             "com.android.settings.mobilenetwork.action.ENHANCED_4G_LTE_CHANGED";
58 
59     /**
60      * Action for mobile network settings activity which
61      * allows setting configuration for Enhanced 4G LTE
62      * related settings
63      */
64     public static final String ACTION_MOBILE_NETWORK_SETTINGS_ACTIVITY =
65             "android.settings.NETWORK_OPERATOR_SETTINGS";
66 
67     private final Context mContext;
68 
69     /**
70      * Phone package name
71      */
72     private static final String PACKAGE_PHONE = "com.android.phone";
73 
74     /**
75      * String resource type
76      */
77     private static final String RESOURCE_TYPE_STRING = "string";
78 
79     /**
80      * Enhanced 4g lte mode title variant resource name
81      */
82     private static final String RESOURCE_ENHANCED_4G_LTE_MODE_TITLE_VARIANT =
83             "enhanced_4g_lte_mode_title_variant";
84 
85     private static final int MODE_VOLTE = 0;
86     private static final int MODE_ADVANCED_CALL = 1;
87     private static final int MODE_4G_CALLING = 2;
88 
89     @VisibleForTesting
Enhanced4gLteSliceHelper(Context context)90     public Enhanced4gLteSliceHelper(Context context) {
91         mContext = context;
92     }
93 
94     /**
95      * Returns Slice object for enhanced_4g_lte settings.
96      *
97      * If enhanced 4g LTE is not supported for the current carrier, this method will return slice
98      * with not supported message.
99      *
100      * If enhanced 4g LTE is not editable for the current carrier, this method will return slice
101      * with not editable message.
102      *
103      * If enhanced 4g LTE setting can be changed, this method will return the slice to toggle
104      * enhanced 4g LTE option with ACTION_ENHANCED_4G_LTE_CHANGED as endItem.
105      */
createEnhanced4gLteSlice(Uri sliceUri)106     public Slice createEnhanced4gLteSlice(Uri sliceUri) {
107         final int subId = getDefaultVoiceSubId();
108 
109         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
110             Log.d(TAG, "Invalid subscription Id");
111             return null;
112         }
113 
114         if (isCarrierConfigManagerKeyEnabled(
115                 CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL, subId, false)
116                 || !isCarrierConfigManagerKeyEnabled(
117                 CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, subId,
118                 true)) {
119             Log.d(TAG, "Setting is either hidden or not editable");
120             return null;
121         }
122 
123         final VolteQueryImsState queryState = queryImsState(subId);
124         if (!queryState.isVoLteProvisioned()) {
125             Log.d(TAG, "Setting is either not provisioned or not enabled by Platform");
126             return null;
127         }
128 
129         try {
130             return getEnhanced4gLteSlice(sliceUri,
131                     queryState.isEnabledByUser(), subId);
132         } catch (IllegalArgumentException e) {
133             Log.e(TAG, "Unable to read the current Enhanced 4g LTE status", e);
134             return null;
135         }
136     }
137 
138     /**
139      * Builds a toggle slice where the intent takes you to the Enhanced 4G LTE page and the toggle
140      * enables/disables Enhanced 4G LTE mode setting.
141      */
getEnhanced4gLteSlice(Uri sliceUri, boolean isEnhanced4gLteEnabled, int subId)142     private Slice getEnhanced4gLteSlice(Uri sliceUri, boolean isEnhanced4gLteEnabled, int subId) {
143         final IconCompat icon = IconCompat.createWithResource(mContext,
144                 R.drawable.ic_launcher_settings);
145 
146         return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
147                 .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
148                 .addRow(new RowBuilder()
149                         .setTitle(getEnhanced4glteModeTitle(subId))
150                         .addEndItem(
151                                 SliceAction.createToggle(
152                                         getBroadcastIntent(ACTION_ENHANCED_4G_LTE_CHANGED),
153                                         null /* actionTitle */, isEnhanced4gLteEnabled))
154                         .setPrimaryAction(
155                                 SliceAction.createDeeplink(
156                                         getActivityIntent(ACTION_MOBILE_NETWORK_SETTINGS_ACTIVITY),
157                                         icon,
158                                         ListBuilder.ICON_IMAGE,
159                                         getEnhanced4glteModeTitle(subId))))
160                 .build();
161     }
162 
163     /**
164      * Handles Enhanced 4G LTE mode setting change from Enhanced 4G LTE slice and posts
165      * notification. Should be called when intent action is ACTION_ENHANCED_4G_LTE_CHANGED
166      *
167      * @param intent action performed
168      */
handleEnhanced4gLteChanged(Intent intent)169     public void handleEnhanced4gLteChanged(Intent intent) {
170         // skip checking when no toggle state update contained within Intent
171         final boolean newValue = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, false);
172         if (newValue != intent.getBooleanExtra(EXTRA_TOGGLE_STATE, true)) {
173             notifyEnhanced4gLteUpdate();
174             return;
175         }
176 
177         final int subId = getDefaultVoiceSubId();
178         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
179             notifyEnhanced4gLteUpdate();
180             return;
181         }
182 
183         final VolteQueryImsState queryState = queryImsState(subId);
184         final boolean currentValue = queryState.isEnabledByUser()
185                 && queryState.isAllowUserControl();
186         if (newValue == currentValue) {
187             notifyEnhanced4gLteUpdate();
188             return;
189         }
190 
191         // isVoLteProvisioned() is the last item to check since it might block the main thread
192         if (queryState.isVoLteProvisioned()) {
193             setEnhanced4gLteModeSetting(subId, newValue);
194         }
195         notifyEnhanced4gLteUpdate();
196     }
197 
notifyEnhanced4gLteUpdate()198     private void notifyEnhanced4gLteUpdate() {
199         // notify change in slice in any case to get re-queried. This would result in displaying
200         // appropriate message with the updated setting.
201         mContext.getContentResolver().notifyChange(CustomSliceRegistry.ENHANCED_4G_SLICE_URI, null);
202     }
203 
204     @VisibleForTesting
setEnhanced4gLteModeSetting(int subId, boolean isEnabled)205     void setEnhanced4gLteModeSetting(int subId, boolean isEnabled) {
206         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
207             return;
208         }
209         final ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(subId);
210         if (imsMmTelManager == null) {
211             return;
212         }
213         try {
214             imsMmTelManager.setAdvancedCallingSettingEnabled(isEnabled);
215         } catch (IllegalArgumentException exception) {
216             Log.w(TAG, "Unable to change the Enhanced 4g LTE to " + isEnabled + ". subId=" + subId,
217                     exception);
218         }
219     }
220 
getEnhanced4glteModeTitle(int subId)221     private CharSequence getEnhanced4glteModeTitle(int subId) {
222         final int variant4gLteTitleIndex = getCarrierConfigManagerKeyValue(
223                 CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT, subId, 0);
224         final boolean show4GForLTE = isCarrierConfigManagerKeyEnabled(
225                 CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, subId, false);
226         final CharSequence[] variantTitles = mContext.getResources()
227                 .getTextArray(R.array.enhanced_4g_lte_mode_title_variant);
228         int index = MODE_ADVANCED_CALL;
229         if (variant4gLteTitleIndex != MODE_ADVANCED_CALL) {
230             index = show4GForLTE ? MODE_4G_CALLING : MODE_VOLTE;
231         }
232         return variantTitles[index];
233     }
234 
235     /**
236      * Returns {@code true} when the key is enabled for the carrier, and {@code false} otherwise.
237      */
isCarrierConfigManagerKeyEnabled(String key, int subId, boolean defaultValue)238     private boolean isCarrierConfigManagerKeyEnabled(String key, int subId, boolean defaultValue) {
239         boolean result = defaultValue;
240         final PersistableBundle carrierConfig = getCarrierConfig(subId);
241         if (carrierConfig != null) {
242             result = carrierConfig.getBoolean(key, defaultValue);
243         }
244         return result;
245     }
246 
getCarrierConfigManagerKeyValue(String key, int subId, int defaultValue)247     private int getCarrierConfigManagerKeyValue(String key, int subId, int defaultValue) {
248         int result = defaultValue;
249         final PersistableBundle carrierConfig = getCarrierConfig(subId);
250         if (carrierConfig != null) {
251             result = carrierConfig.getInt(key, defaultValue);
252         }
253         return result;
254     }
255 
getCarrierConfig(int subId)256     private PersistableBundle getCarrierConfig(int subId) {
257         final CarrierConfigManager configManager = getCarrierConfigManager();
258         PersistableBundle bundle = null;
259         if (configManager != null) {
260             bundle = configManager.getConfigForSubId(subId);
261         }
262         return bundle;
263     }
264 
getCarrierConfigManager()265     protected CarrierConfigManager getCarrierConfigManager() {
266         return mContext.getSystemService(CarrierConfigManager.class);
267     }
268 
getBroadcastIntent(String action)269     private PendingIntent getBroadcastIntent(String action) {
270         final Intent intent = new Intent(action);
271         intent.setClass(mContext, SliceBroadcastReceiver.class);
272         return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
273                 PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
274     }
275 
276     /**
277      * Returns the current default voice subId obtained from SubscriptionManager
278      */
getDefaultVoiceSubId()279     protected int getDefaultVoiceSubId() {
280         return SubscriptionManager.getDefaultVoiceSubscriptionId();
281     }
282 
283     /**
284      * Returns PendingIntent to start activity specified by action
285      */
getActivityIntent(String action)286     private PendingIntent getActivityIntent(String action) {
287         final Intent intent = new Intent(action);
288         intent.setPackage(SETTINGS_PACKAGE_NAME);
289         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
290         return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent,
291                 PendingIntent.FLAG_IMMUTABLE);
292     }
293 
294     @VisibleForTesting
queryImsState(int subId)295     VolteQueryImsState queryImsState(int subId) {
296         return new VolteQueryImsState(mContext, subId);
297     }
298 }
299 
300