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