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