1 /* 2 * Copyright (C) 2016 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.applications.specialaccess.premiumsms; 18 19 import android.annotation.Nullable; 20 import android.app.Application; 21 import android.app.settings.SettingsEnums; 22 import android.content.Context; 23 import android.os.Bundle; 24 import android.provider.SearchIndexableResource; 25 import android.view.View; 26 27 import androidx.annotation.VisibleForTesting; 28 import androidx.preference.DropDownPreference; 29 import androidx.preference.Preference; 30 import androidx.preference.Preference.OnPreferenceChangeListener; 31 import androidx.preference.PreferenceScreen; 32 import androidx.preference.PreferenceViewHolder; 33 34 import com.android.internal.telephony.SmsUsageMonitor; 35 import com.android.settings.R; 36 import com.android.settings.applications.AppStateBaseBridge.Callback; 37 import com.android.settings.applications.AppStateSmsPremBridge; 38 import com.android.settings.applications.AppStateSmsPremBridge.SmsState; 39 import com.android.settings.overlay.FeatureFactory; 40 import com.android.settings.search.BaseSearchIndexProvider; 41 import com.android.settings.search.Indexable; 42 import com.android.settings.widget.EmptyTextSettings; 43 import com.android.settingslib.applications.ApplicationsState; 44 import com.android.settingslib.applications.ApplicationsState.AppEntry; 45 import com.android.settingslib.applications.ApplicationsState.Callbacks; 46 import com.android.settingslib.applications.ApplicationsState.Session; 47 import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 48 import com.android.settingslib.search.SearchIndexable; 49 import com.android.settingslib.widget.FooterPreference; 50 51 import java.util.ArrayList; 52 import java.util.List; 53 54 @SearchIndexable 55 public class PremiumSmsAccess extends EmptyTextSettings 56 implements Callback, Callbacks, OnPreferenceChangeListener { 57 58 private ApplicationsState mApplicationsState; 59 private AppStateSmsPremBridge mSmsBackend; 60 private Session mSession; 61 62 @Override onCreate(Bundle icicle)63 public void onCreate(Bundle icicle) { 64 super.onCreate(icicle); 65 mApplicationsState = ApplicationsState.getInstance((Application) 66 getContext().getApplicationContext()); 67 mSession = mApplicationsState.newSession(this, getSettingsLifecycle()); 68 mSmsBackend = new AppStateSmsPremBridge(getContext(), mApplicationsState, this); 69 } 70 71 @Override onViewCreated(View view, @Nullable Bundle savedInstanceState)72 public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { 73 super.onViewCreated(view, savedInstanceState); 74 setLoading(true, false); 75 } 76 77 @Override onResume()78 public void onResume() { 79 super.onResume(); 80 mSmsBackend.resume(); 81 } 82 83 @Override onPause()84 public void onPause() { 85 mSmsBackend.pause(); 86 super.onPause(); 87 } 88 89 @Override onDestroy()90 public void onDestroy() { 91 mSmsBackend.release(); 92 super.onDestroy(); 93 } 94 95 @Override getPreferenceScreenResId()96 protected int getPreferenceScreenResId() { 97 return R.xml.premium_sms_settings; 98 } 99 100 @Override getMetricsCategory()101 public int getMetricsCategory() { 102 return SettingsEnums.PREMIUM_SMS_ACCESS; 103 } 104 105 @Override onPreferenceChange(Preference preference, Object newValue)106 public boolean onPreferenceChange(Preference preference, Object newValue) { 107 PremiumSmsPreference pref = (PremiumSmsPreference) preference; 108 int smsState = Integer.parseInt((String) newValue); 109 logSpecialPermissionChange(smsState, pref.mAppEntry.info.packageName); 110 mSmsBackend.setSmsState(pref.mAppEntry.info.packageName, smsState); 111 return true; 112 } 113 114 @VisibleForTesting logSpecialPermissionChange(int smsState, String packageName)115 void logSpecialPermissionChange(int smsState, String packageName) { 116 int category = SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN; 117 switch (smsState) { 118 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER: 119 category = SettingsEnums.APP_SPECIAL_PERMISSION_PREMIUM_SMS_ASK; 120 break; 121 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW: 122 category = SettingsEnums.APP_SPECIAL_PERMISSION_PREMIUM_SMS_DENY; 123 break; 124 case SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW: 125 category = SettingsEnums. 126 APP_SPECIAL_PERMISSION_PREMIUM_SMS_ALWAYS_ALLOW; 127 break; 128 } 129 if (category != SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN) { 130 // TODO(117860032): Category is wrong. It should be defined in SettingsEnums. 131 final MetricsFeatureProvider metricsFeatureProvider = 132 FeatureFactory.getFactory(getContext()).getMetricsFeatureProvider(); 133 metricsFeatureProvider.action( 134 metricsFeatureProvider.getAttribution(getActivity()), 135 category, 136 getMetricsCategory(), 137 packageName, 138 smsState); 139 } 140 } 141 updatePrefs(ArrayList<AppEntry> apps)142 private void updatePrefs(ArrayList<AppEntry> apps) { 143 if (apps == null) return; 144 setEmptyText(R.string.premium_sms_none); 145 setLoading(false, true); 146 final PreferenceScreen screen = getPreferenceScreen(); 147 screen.removeAll(); 148 screen.setOrderingAsAdded(true); 149 150 for (int i = 0; i < apps.size(); i++) { 151 final PremiumSmsPreference smsPreference = 152 new PremiumSmsPreference(apps.get(i), getPrefContext()); 153 smsPreference.setOnPreferenceChangeListener(this); 154 screen.addPreference(smsPreference); 155 } 156 if (apps.size() != 0) { 157 FooterPreference footer = new FooterPreference(getPrefContext()); 158 footer.setTitle(R.string.premium_sms_warning); 159 screen.addPreference(footer); 160 } 161 } 162 update()163 private void update() { 164 updatePrefs(mSession.rebuild(AppStateSmsPremBridge.FILTER_APP_PREMIUM_SMS, 165 ApplicationsState.ALPHA_COMPARATOR)); 166 } 167 168 @Override onExtraInfoUpdated()169 public void onExtraInfoUpdated() { 170 update(); 171 } 172 173 @Override onRebuildComplete(ArrayList<AppEntry> apps)174 public void onRebuildComplete(ArrayList<AppEntry> apps) { 175 updatePrefs(apps); 176 } 177 178 @Override onRunningStateChanged(boolean running)179 public void onRunningStateChanged(boolean running) { 180 181 } 182 183 @Override onPackageListChanged()184 public void onPackageListChanged() { 185 186 } 187 188 @Override onPackageIconChanged()189 public void onPackageIconChanged() { 190 191 } 192 193 @Override onPackageSizeChanged(String packageName)194 public void onPackageSizeChanged(String packageName) { 195 196 } 197 198 @Override onAllSizesComputed()199 public void onAllSizesComputed() { 200 201 } 202 203 @Override onLauncherInfoChanged()204 public void onLauncherInfoChanged() { 205 206 } 207 208 @Override onLoadEntriesCompleted()209 public void onLoadEntriesCompleted() { 210 211 } 212 213 private class PremiumSmsPreference extends DropDownPreference { 214 private final AppEntry mAppEntry; 215 PremiumSmsPreference(AppEntry appEntry, Context context)216 public PremiumSmsPreference(AppEntry appEntry, Context context) { 217 super(context); 218 mAppEntry = appEntry; 219 mAppEntry.ensureLabel(context); 220 setTitle(mAppEntry.label); 221 if (mAppEntry.icon != null) { 222 setIcon(mAppEntry.icon); 223 } 224 setEntries(R.array.security_settings_premium_sms_values); 225 setEntryValues(new CharSequence[]{ 226 String.valueOf(SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ASK_USER), 227 String.valueOf(SmsUsageMonitor.PREMIUM_SMS_PERMISSION_NEVER_ALLOW), 228 String.valueOf(SmsUsageMonitor.PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW), 229 }); 230 setValue(String.valueOf(getCurrentValue())); 231 setSummary("%s"); 232 } 233 getCurrentValue()234 private int getCurrentValue() { 235 return mAppEntry.extraInfo instanceof SmsState 236 ? ((SmsState) mAppEntry.extraInfo).smsState 237 : SmsUsageMonitor.PREMIUM_SMS_PERMISSION_UNKNOWN; 238 } 239 240 @Override onBindViewHolder(PreferenceViewHolder holder)241 public void onBindViewHolder(PreferenceViewHolder holder) { 242 if (getIcon() == null) { 243 holder.itemView.post(new Runnable() { 244 @Override 245 public void run() { 246 mApplicationsState.ensureIcon(mAppEntry); 247 setIcon(mAppEntry.icon); 248 } 249 }); 250 } 251 super.onBindViewHolder(holder); 252 } 253 } 254 255 public static final Indexable.SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER = 256 new BaseSearchIndexProvider() { 257 @Override 258 public List<SearchIndexableResource> getXmlResourcesToIndex(Context context, 259 boolean enabled) { 260 final ArrayList<SearchIndexableResource> result = new ArrayList<>(); 261 262 final SearchIndexableResource sir = new SearchIndexableResource(context); 263 sir.xmlResId = R.xml.premium_sms_settings; 264 result.add(sir); 265 return result; 266 } 267 }; 268 } 269