1 /* 2 * Copyright (C) 2024 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 android.content.Context; 20 import android.os.Build; 21 import android.safetycenter.SafetyCenterManager; 22 import android.telephony.SubscriptionInfo; 23 import android.telephony.TelephonyManager; 24 import android.util.Log; 25 26 import androidx.annotation.NonNull; 27 import androidx.annotation.VisibleForTesting; 28 29 import com.android.settings.network.SubscriptionUtil; 30 31 import java.util.List; 32 33 /** 34 * {@link TelephonyTogglePreferenceController} for accessing Cellular Security settings through 35 * Safety Center. 36 */ 37 public class CellularSecurityNotificationsPreferenceController extends 38 TelephonyTogglePreferenceController { 39 40 private static final String LOG_TAG = "CellularSecurityNotificationsPreferenceController"; 41 42 private TelephonyManager mTelephonyManager; 43 @VisibleForTesting 44 protected SafetyCenterManager mSafetyCenterManager; 45 46 /** 47 * Class constructor of "Cellular Security" preference. 48 * 49 * @param context of settings 50 * @param prefKey assigned within UI entry of XML file 51 */ CellularSecurityNotificationsPreferenceController( @onNull Context context, @NonNull String prefKey)52 public CellularSecurityNotificationsPreferenceController( 53 @NonNull Context context, @NonNull String prefKey) { 54 super(context, prefKey); 55 mTelephonyManager = mContext.getSystemService(TelephonyManager.class); 56 mSafetyCenterManager = mContext.getSystemService(SafetyCenterManager.class); 57 } 58 59 /** 60 * Initialization based on a given subscription id. 61 * 62 * @param subId is the subscription id 63 * @return this instance after initialization 64 */ init(@onNull int subId)65 @NonNull public CellularSecurityNotificationsPreferenceController init(@NonNull int subId) { 66 mTelephonyManager = mContext.getSystemService(TelephonyManager.class) 67 .createForSubscriptionId(subId); 68 return this; 69 } 70 71 @Override getAvailabilityStatus(int subId)72 public int getAvailabilityStatus(int subId) { 73 if (!isSafetyCenterSupported()) { 74 return UNSUPPORTED_ON_DEVICE; 75 } 76 77 // Check there are valid SIM cards which can be displayed to the user, otherwise this 78 // setting should not be shown. 79 List<SubscriptionInfo> availableSubs = SubscriptionUtil.getAvailableSubscriptions(mContext); 80 if (availableSubs.isEmpty()) { 81 return CONDITIONALLY_UNAVAILABLE; 82 } 83 84 // Checking for hardware support, i.e. IRadio AIDL version must be >= 2.2 85 try { 86 areNotificationsEnabled(); 87 } catch (UnsupportedOperationException e) { 88 Log.i(LOG_TAG, "Cellular security notifications are unsupported: " + e.getMessage()); 89 return UNSUPPORTED_ON_DEVICE; 90 } 91 92 return AVAILABLE; 93 } 94 95 /** 96 * Return {@code true} if cellular security notifications are on 97 * 98 * <p><b>NOTE:</b> This method returns the active state of the preference controller and is not 99 * the parameter passed into {@link #setChecked(boolean)}, which is instead the requested future 100 * state. 101 */ 102 @Override isChecked()103 public boolean isChecked() { 104 try { 105 // Note: the default behavior for this toggle is disabled (as the underlying 106 // TelephonyManager APIs are disabled by default) 107 return areNotificationsEnabled(); 108 } catch (Exception e) { 109 Log.e(LOG_TAG, 110 "Failed isNullCipherNotificationsEnabled and " 111 + "isCellularIdentifierDisclosureNotificationsEnabled." 112 + "Defaulting toggle to checked = true. Exception: " 113 + e.getMessage()); 114 return false; 115 } 116 } 117 118 /** 119 * Called when a user preference changes on the toggle. We pass this info on to the Telephony 120 * Framework so that the modem can be updated with the user's preference. 121 * 122 * <p>See {@link com.android.settings.core.TogglePreferenceController#setChecked(boolean)} for 123 * details. 124 * 125 * @param isChecked The toggle value that we're being requested to enforce. A value of {@code 126 * true} denotes that both (1) null cipher/integrity notifications, and 127 * (2) IMSI disclosure notifications will be enabled by the modem after this 128 * function completes, if they are not already. 129 */ 130 @Override setChecked(boolean isChecked)131 public boolean setChecked(boolean isChecked) { 132 if (isChecked) { 133 Log.i(LOG_TAG, "Enabling cellular security notifications."); 134 } else { 135 Log.i(LOG_TAG, "Disabling cellular security notifications."); 136 } 137 138 try { 139 setNotifications(isChecked); 140 } catch (Exception e) { 141 Log.e(LOG_TAG, 142 "Failed setCellularIdentifierDisclosureNotificationEnabled or " 143 + " setNullCipherNotificationsEnabled. Setting not updated. Exception: " 144 + e.getMessage()); 145 // Reset to defaults so we don't end up in an inconsistent state 146 setNotifications(!isChecked); 147 return false; 148 } 149 return true; 150 } 151 setNotifications(boolean isChecked)152 private void setNotifications(boolean isChecked) { 153 mTelephonyManager.setEnableCellularIdentifierDisclosureNotifications(isChecked); 154 mTelephonyManager.setNullCipherNotificationsEnabled(isChecked); 155 } 156 areNotificationsEnabled()157 private boolean areNotificationsEnabled() { 158 if (mTelephonyManager == null) { 159 Log.w(LOG_TAG, "Telephony manager not yet initialized"); 160 mTelephonyManager = mContext.getSystemService(TelephonyManager.class); 161 } 162 return mTelephonyManager.isNullCipherNotificationsEnabled() 163 && mTelephonyManager.isCellularIdentifierDisclosureNotificationsEnabled(); 164 } 165 isSafetyCenterSupported()166 protected boolean isSafetyCenterSupported() { 167 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { 168 return false; 169 } 170 mSafetyCenterManager = mContext.getSystemService( 171 SafetyCenterManager.class); 172 if (mSafetyCenterManager == null) { 173 return false; 174 } 175 return mSafetyCenterManager.isSafetyCenterEnabled(); 176 } 177 } 178