1 /* 2 * Copyright 2019 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.car.settings.applications.specialaccess; 18 19 import android.car.drivingstate.CarUxRestrictions; 20 import android.content.Context; 21 import android.telephony.SmsManager; 22 23 import androidx.annotation.VisibleForTesting; 24 import androidx.preference.ListPreference; 25 import androidx.preference.Preference; 26 import androidx.preference.PreferenceGroup; 27 28 import com.android.car.settings.R; 29 import com.android.car.settings.common.FragmentController; 30 import com.android.car.settings.common.Logger; 31 import com.android.car.settings.common.PreferenceController; 32 import com.android.settingslib.applications.ApplicationsState.AppEntry; 33 import com.android.settingslib.applications.ApplicationsState.AppFilter; 34 35 import java.util.List; 36 37 /** 38 * Displays the list of apps which have a known premium SMS access state. When a user selects an 39 * app, they are shown a dialog which allows them to configure the state to one of: 40 * 41 * <ul> 42 * <li>Ask - the user will be prompted before app sends premium SMS. 43 * <li>Never allow - app can never send premium SMS. 44 * <li>Always allow - app can automatically send premium SMS. 45 * </ul> 46 */ 47 public class PremiumSmsAccessPreferenceController extends PreferenceController<PreferenceGroup> { 48 49 private static final Logger LOG = new Logger(PremiumSmsAccessPreferenceController.class); 50 51 private static final AppFilter FILTER_SMS_STATE_KNOWN = new AppFilter() { 52 @Override 53 public void init() { 54 // No op. 55 } 56 57 @Override 58 public boolean filterApp(AppEntry info) { 59 return info.extraInfo != null 60 && (Integer) info.extraInfo != SmsManager.PREMIUM_SMS_CONSENT_UNKNOWN; 61 } 62 }; 63 64 private final SmsManager mSmsManager; 65 66 private final Preference.OnPreferenceChangeListener mOnPreferenceChangeListener = 67 new Preference.OnPreferenceChangeListener() { 68 @Override 69 public boolean onPreferenceChange(Preference preference, Object newValue) { 70 PremiumSmsPreference appPreference = (PremiumSmsPreference) preference; 71 AppEntry entry = appPreference.mEntry; 72 int smsState = Integer.parseInt((String) newValue); 73 if (smsState != (Integer) entry.extraInfo) { 74 mSmsManager.setPremiumSmsConsent(entry.info.packageName, smsState); 75 // Update the extra info of this entry so that it reflects the new state. 76 mAppEntryListManager.forceUpdate(entry); 77 return true; 78 } 79 return false; 80 } 81 }; 82 83 private final AppEntryListManager.Callback mCallback = new AppEntryListManager.Callback() { 84 @Override 85 public void onAppEntryListChanged(List<AppEntry> entries) { 86 mEntries = entries; 87 refreshUi(); 88 } 89 }; 90 91 private AppEntryListManager mAppEntryListManager; 92 private List<AppEntry> mEntries; 93 PremiumSmsAccessPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions)94 public PremiumSmsAccessPreferenceController(Context context, String preferenceKey, 95 FragmentController fragmentController, CarUxRestrictions uxRestrictions) { 96 this(context, preferenceKey, fragmentController, uxRestrictions, SmsManager.getDefault(), 97 new AppEntryListManager(context)); 98 } 99 100 @VisibleForTesting PremiumSmsAccessPreferenceController(Context context, String preferenceKey, FragmentController fragmentController, CarUxRestrictions uxRestrictions, SmsManager smsManager, AppEntryListManager appEntryListManager)101 PremiumSmsAccessPreferenceController(Context context, String preferenceKey, 102 FragmentController fragmentController, CarUxRestrictions uxRestrictions, 103 SmsManager smsManager, AppEntryListManager appEntryListManager) { 104 super(context, preferenceKey, fragmentController, uxRestrictions); 105 mSmsManager = smsManager; 106 mAppEntryListManager = appEntryListManager; 107 } 108 109 @Override getPreferenceType()110 protected Class<PreferenceGroup> getPreferenceType() { 111 return PreferenceGroup.class; 112 } 113 114 @Override onCreateInternal()115 protected void onCreateInternal() { 116 mAppEntryListManager.init(new AppStatePremiumSmsBridge(mSmsManager), 117 () -> FILTER_SMS_STATE_KNOWN, mCallback); 118 } 119 120 @Override onStartInternal()121 protected void onStartInternal() { 122 mAppEntryListManager.start(); 123 } 124 125 @Override onStopInternal()126 protected void onStopInternal() { 127 mAppEntryListManager.stop(); 128 } 129 130 @Override onDestroyInternal()131 protected void onDestroyInternal() { 132 mAppEntryListManager.destroy(); 133 } 134 135 @Override updateState(PreferenceGroup preference)136 protected void updateState(PreferenceGroup preference) { 137 if (mEntries == null) { 138 // Still loading. 139 return; 140 } 141 preference.removeAll(); 142 for (AppEntry entry : mEntries) { 143 Preference appPreference = new PremiumSmsPreference(getContext(), entry); 144 appPreference.setOnPreferenceChangeListener(mOnPreferenceChangeListener); 145 preference.addPreference(appPreference); 146 } 147 } 148 149 private static class PremiumSmsPreference extends ListPreference { 150 151 private final AppEntry mEntry; 152 PremiumSmsPreference(Context context, AppEntry entry)153 PremiumSmsPreference(Context context, AppEntry entry) { 154 super(context); 155 String key = entry.info.packageName + "|" + entry.info.uid; 156 setKey(key); 157 setTitle(entry.label); 158 setIcon(entry.icon); 159 setPersistent(false); 160 setEntries(R.array.premium_sms_access_values); 161 setEntryValues(new CharSequence[]{ 162 String.valueOf(SmsManager.PREMIUM_SMS_CONSENT_ASK_USER), 163 String.valueOf(SmsManager.PREMIUM_SMS_CONSENT_NEVER_ALLOW), 164 String.valueOf(SmsManager.PREMIUM_SMS_CONSENT_ALWAYS_ALLOW) 165 }); 166 setValue(String.valueOf(entry.extraInfo)); 167 setSummary("%s"); 168 mEntry = entry; 169 } 170 } 171 } 172