• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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.utils;
18 
19 import android.annotation.Nullable;
20 import android.app.ActivityManager;
21 import android.app.AlertDialog;
22 import android.app.Dialog;
23 import android.app.Fragment;
24 import android.app.admin.DevicePolicyManager;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.pm.PackageItemInfo;
28 import android.content.pm.PackageManager;
29 import android.content.pm.ServiceInfo;
30 import android.os.Bundle;
31 import android.os.UserHandle;
32 import android.os.UserManager;
33 import android.support.v14.preference.SwitchPreference;
34 import android.support.v7.preference.PreferenceScreen;
35 import android.util.IconDrawableFactory;
36 import android.util.Log;
37 import android.view.View;
38 
39 import com.android.internal.logging.nano.MetricsProto;
40 import com.android.settings.R;
41 import com.android.settings.Utils;
42 import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
43 import com.android.settings.notification.EmptyTextSettings;
44 import com.android.settings.widget.AppSwitchPreference;
45 import com.android.settingslib.applications.ServiceListing;
46 
47 import java.util.List;
48 
49 public abstract class ManagedServiceSettings extends EmptyTextSettings {
50     private static final String TAG = "ManagedServiceSettings";
51     private final Config mConfig;
52 
53     protected Context mContext;
54     private PackageManager mPm;
55     private DevicePolicyManager mDpm;
56     private ServiceListing mServiceListing;
57     private IconDrawableFactory mIconDrawableFactory;
58 
getConfig()59     abstract protected Config getConfig();
60 
ManagedServiceSettings()61     public ManagedServiceSettings() {
62         mConfig = getConfig();
63     }
64 
65     @Override
onCreate(Bundle icicle)66     public void onCreate(Bundle icicle) {
67         super.onCreate(icicle);
68 
69         mContext = getActivity();
70         mPm = mContext.getPackageManager();
71         mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
72         mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);
73         mServiceListing = new ServiceListing.Builder(mContext)
74                 .setPermission(mConfig.permission)
75                 .setIntentAction(mConfig.intentAction)
76                 .setNoun(mConfig.noun)
77                 .setSetting(mConfig.setting)
78                 .setTag(mConfig.tag)
79                 .build();
80         mServiceListing.addCallback(this::updateList);
81         setPreferenceScreen(getPreferenceManager().createPreferenceScreen(mContext));
82     }
83 
84     @Override
onViewCreated(View view, @Nullable Bundle savedInstanceState)85     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
86         super.onViewCreated(view, savedInstanceState);
87         setEmptyText(mConfig.emptyText);
88     }
89 
90     @Override
onResume()91     public void onResume() {
92         super.onResume();
93         if (!ActivityManager.isLowRamDeviceStatic()) {
94             mServiceListing.reload();
95             mServiceListing.setListening(true);
96         } else {
97             setEmptyText(R.string.disabled_low_ram_device);
98         }
99     }
100 
101     @Override
onPause()102     public void onPause() {
103         super.onPause();
104         mServiceListing.setListening(false);
105     }
106 
updateList(List<ServiceInfo> services)107     private void updateList(List<ServiceInfo> services) {
108         UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
109         final int managedProfileId = Utils.getManagedProfileId(um, UserHandle.myUserId());
110 
111         final PreferenceScreen screen = getPreferenceScreen();
112         screen.removeAll();
113         services.sort(new PackageItemInfo.DisplayNameComparator(mPm));
114         for (ServiceInfo service : services) {
115             final ComponentName cn = new ComponentName(service.packageName, service.name);
116             CharSequence title = null;
117             try {
118                 title = mPm.getApplicationInfoAsUser(
119                         service.packageName, 0, getCurrentUser(managedProfileId)).loadLabel(mPm);
120             } catch (PackageManager.NameNotFoundException e) {
121                 // unlikely, as we are iterating over live services.
122                 Log.e(TAG, "can't find package name", e);
123             }
124             final String summary = service.loadLabel(mPm).toString();
125             final SwitchPreference pref = new AppSwitchPreference(getPrefContext());
126             pref.setPersistent(false);
127             pref.setIcon(mIconDrawableFactory.getBadgedIcon(service, service.applicationInfo,
128                     UserHandle.getUserId(service.applicationInfo.uid)));
129             if (title != null && !title.equals(summary)) {
130                 pref.setTitle(title);
131                 pref.setSummary(summary);
132             } else {
133                 pref.setTitle(summary);
134             }
135             pref.setKey(cn.flattenToString());
136             pref.setChecked(isServiceEnabled(cn));
137             if (managedProfileId != UserHandle.USER_NULL
138                     && !mDpm.isNotificationListenerServicePermitted(
139                             service.packageName, managedProfileId)) {
140                 pref.setSummary(R.string.work_profile_notification_access_blocked_summary);
141             }
142             pref.setOnPreferenceChangeListener((preference, newValue) -> {
143                 final boolean enable = (boolean) newValue;
144                 return setEnabled(cn, summary, enable);
145             });
146             pref.setKey(cn.flattenToString());
147             screen.addPreference(pref);
148         }
149         highlightPreferenceIfNeeded();
150     }
151 
getCurrentUser(int managedProfileId)152     private int getCurrentUser(int managedProfileId) {
153         if (managedProfileId != UserHandle.USER_NULL) {
154             return managedProfileId;
155         }
156         return UserHandle.myUserId();
157     }
158 
isServiceEnabled(ComponentName cn)159     protected boolean isServiceEnabled(ComponentName cn) {
160         return mServiceListing.isEnabled(cn);
161     }
162 
setEnabled(ComponentName service, String title, boolean enable)163     protected boolean setEnabled(ComponentName service, String title, boolean enable) {
164         if (!enable) {
165             // the simple version: disabling
166             mServiceListing.setEnabled(service, false);
167             return true;
168         } else {
169             if (mServiceListing.isEnabled(service)) {
170                 return true; // already enabled
171             }
172             // show a scary dialog
173             new ScaryWarningDialogFragment()
174                     .setServiceInfo(service, title, this)
175                     .show(getFragmentManager(), "dialog");
176             return false;
177         }
178     }
179 
enable(ComponentName service)180     protected void enable(ComponentName service) {
181         mServiceListing.setEnabled(service, true);
182     }
183 
184     public static class ScaryWarningDialogFragment extends InstrumentedDialogFragment {
185         private static final String KEY_COMPONENT = "c";
186         private static final String KEY_LABEL = "l";
187 
188         @Override
getMetricsCategory()189         public int getMetricsCategory() {
190             return MetricsProto.MetricsEvent.DIALOG_SERVICE_ACCESS_WARNING;
191         }
192 
setServiceInfo(ComponentName cn, String label, Fragment target)193         public ScaryWarningDialogFragment setServiceInfo(ComponentName cn, String label,
194                 Fragment target) {
195             Bundle args = new Bundle();
196             args.putString(KEY_COMPONENT, cn.flattenToString());
197             args.putString(KEY_LABEL, label);
198             setArguments(args);
199             setTargetFragment(target, 0);
200             return this;
201         }
202 
203         @Override
onCreateDialog(Bundle savedInstanceState)204         public Dialog onCreateDialog(Bundle savedInstanceState) {
205             final Bundle args = getArguments();
206             final String label = args.getString(KEY_LABEL);
207             final ComponentName cn = ComponentName.unflattenFromString(args
208                     .getString(KEY_COMPONENT));
209             ManagedServiceSettings parent = (ManagedServiceSettings) getTargetFragment();
210 
211             final String title = getResources().getString(parent.mConfig.warningDialogTitle, label);
212             final String summary = getResources().getString(parent.mConfig.warningDialogSummary,
213                     label);
214             return new AlertDialog.Builder(getContext())
215                     .setMessage(summary)
216                     .setTitle(title)
217                     .setCancelable(true)
218                     .setPositiveButton(R.string.allow,
219                             (dialog, id) -> parent.enable(cn))
220                     .setNegativeButton(R.string.deny,
221                             (dialog, id) -> {
222                                 // pass
223                             })
224                     .create();
225         }
226     }
227 
228     public static class Config {
229         public final String tag;
230         public final String setting;
231         public final String intentAction;
232         public final String permission;
233         public final String noun;
234         public final int warningDialogTitle;
235         public final int warningDialogSummary;
236         public final int emptyText;
237 
Config(String tag, String setting, String intentAction, String permission, String noun, int warningDialogTitle, int warningDialogSummary, int emptyText)238         private Config(String tag, String setting, String intentAction, String permission,
239                 String noun, int warningDialogTitle, int warningDialogSummary, int emptyText) {
240             this.tag = tag;
241             this.setting = setting;
242             this.intentAction = intentAction;
243             this.permission = permission;
244             this.noun = noun;
245             this.warningDialogTitle = warningDialogTitle;
246             this.warningDialogSummary = warningDialogSummary;
247             this.emptyText = emptyText;
248         }
249 
250         public static class Builder{
251             private String mTag;
252             private String mSetting;
253             private String mIntentAction;
254             private String mPermission;
255             private String mNoun;
256             private int mWarningDialogTitle;
257             private int mWarningDialogSummary;
258             private int mEmptyText;
259 
setTag(String tag)260             public Builder setTag(String tag) {
261                 mTag = tag;
262                 return this;
263             }
264 
setSetting(String setting)265             public Builder setSetting(String setting) {
266                 mSetting = setting;
267                 return this;
268             }
269 
setIntentAction(String intentAction)270             public Builder setIntentAction(String intentAction) {
271                 mIntentAction = intentAction;
272                 return this;
273             }
274 
setPermission(String permission)275             public Builder setPermission(String permission) {
276                 mPermission = permission;
277                 return this;
278             }
279 
setNoun(String noun)280             public Builder setNoun(String noun) {
281                 mNoun = noun;
282                 return this;
283             }
284 
setWarningDialogTitle(int warningDialogTitle)285             public Builder setWarningDialogTitle(int warningDialogTitle) {
286                 mWarningDialogTitle = warningDialogTitle;
287                 return this;
288             }
289 
setWarningDialogSummary(int warningDialogSummary)290             public Builder setWarningDialogSummary(int warningDialogSummary) {
291                 mWarningDialogSummary = warningDialogSummary;
292                 return this;
293             }
294 
setEmptyText(int emptyText)295             public Builder setEmptyText(int emptyText) {
296                 mEmptyText = emptyText;
297                 return this;
298             }
299 
build()300             public Config build() {
301                 return new Config(mTag, mSetting, mIntentAction, mPermission, mNoun,
302                         mWarningDialogTitle, mWarningDialogSummary, mEmptyText);
303             }
304         }
305     }
306 
307 }
308