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.AlertDialog;
21 import android.app.Dialog;
22 import android.app.Fragment;
23 import android.app.admin.DevicePolicyManager;
24 import android.content.ComponentName;
25 import android.content.Context;
26 import android.content.DialogInterface;
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.Preference;
35 import android.support.v7.preference.Preference.OnPreferenceChangeListener;
36 import android.support.v7.preference.PreferenceScreen;
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 
45 import java.util.Collections;
46 import java.util.List;
47 
48 public abstract class ManagedServiceSettings extends EmptyTextSettings {
49     private final Config mConfig;
50 
51     protected Context mContext;
52     private PackageManager mPM;
53     private DevicePolicyManager mDpm;
54     protected ServiceListing mServiceListing;
55 
getConfig()56     abstract protected Config getConfig();
57 
ManagedServiceSettings()58     public ManagedServiceSettings() {
59         mConfig = getConfig();
60     }
61 
62     @Override
onCreate(Bundle icicle)63     public void onCreate(Bundle icicle) {
64         super.onCreate(icicle);
65 
66         mContext = getActivity();
67         mPM = mContext.getPackageManager();
68         mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
69         mServiceListing = new ServiceListing(mContext, mConfig);
70         mServiceListing.addCallback(new ServiceListing.Callback() {
71             @Override
72             public void onServicesReloaded(List<ServiceInfo> services) {
73                 updateList(services);
74             }
75         });
76         setPreferenceScreen(getPreferenceManager().createPreferenceScreen(mContext));
77     }
78 
79     @Override
onViewCreated(View view, @Nullable Bundle savedInstanceState)80     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
81         super.onViewCreated(view, savedInstanceState);
82         setEmptyText(mConfig.emptyText);
83     }
84 
85     @Override
onResume()86     public void onResume() {
87         super.onResume();
88         mServiceListing.reload();
89         mServiceListing.setListening(true);
90     }
91 
92     @Override
onPause()93     public void onPause() {
94         super.onPause();
95         mServiceListing.setListening(false);
96     }
97 
updateList(List<ServiceInfo> services)98     private void updateList(List<ServiceInfo> services) {
99         UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
100         final int managedProfileId = Utils.getManagedProfileId(um, UserHandle.myUserId());
101 
102         final PreferenceScreen screen = getPreferenceScreen();
103         screen.removeAll();
104         Collections.sort(services, new PackageItemInfo.DisplayNameComparator(mPM));
105         for (ServiceInfo service : services) {
106             final ComponentName cn = new ComponentName(service.packageName, service.name);
107             final String title = service.loadLabel(mPM).toString();
108             final SwitchPreference pref = new SwitchPreference(getPrefContext());
109             pref.setPersistent(false);
110             pref.setIcon(service.loadIcon(mPM));
111             pref.setTitle(title);
112             pref.setChecked(mServiceListing.isEnabled(cn));
113             if (managedProfileId != UserHandle.USER_NULL
114                     && !mDpm.isNotificationListenerServicePermitted(
115                             service.packageName, managedProfileId)) {
116                 pref.setSummary(R.string.work_profile_notification_access_blocked_summary);
117             }
118             pref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
119                 @Override
120                 public boolean onPreferenceChange(Preference preference, Object newValue) {
121                     final boolean enable = (boolean) newValue;
122                     return setEnabled(cn, title, enable);
123                 }
124             });
125             screen.addPreference(pref);
126         }
127     }
128 
setEnabled(ComponentName service, String title, boolean enable)129     protected boolean setEnabled(ComponentName service, String title, boolean enable) {
130         if (!enable) {
131             // the simple version: disabling
132             mServiceListing.setEnabled(service, false);
133             return true;
134         } else {
135             if (mServiceListing.isEnabled(service)) {
136                 return true; // already enabled
137             }
138             // show a scary dialog
139             new ScaryWarningDialogFragment()
140                     .setServiceInfo(service, title, this)
141                     .show(getFragmentManager(), "dialog");
142             return false;
143         }
144     }
145 
146     public static class ScaryWarningDialogFragment extends InstrumentedDialogFragment {
147         static final String KEY_COMPONENT = "c";
148         static final String KEY_LABEL = "l";
149 
150         @Override
getMetricsCategory()151         public int getMetricsCategory() {
152             return MetricsProto.MetricsEvent.DIALOG_SERVICE_ACCESS_WARNING;
153         }
154 
setServiceInfo(ComponentName cn, String label, Fragment target)155         public ScaryWarningDialogFragment setServiceInfo(ComponentName cn, String label,
156                 Fragment target) {
157             Bundle args = new Bundle();
158             args.putString(KEY_COMPONENT, cn.flattenToString());
159             args.putString(KEY_LABEL, label);
160             setArguments(args);
161             setTargetFragment(target, 0);
162             return this;
163         }
164 
165         @Override
onCreateDialog(Bundle savedInstanceState)166         public Dialog onCreateDialog(Bundle savedInstanceState) {
167             final Bundle args = getArguments();
168             final String label = args.getString(KEY_LABEL);
169             final ComponentName cn = ComponentName.unflattenFromString(args
170                     .getString(KEY_COMPONENT));
171             ManagedServiceSettings parent = (ManagedServiceSettings) getTargetFragment();
172 
173             final String title = getResources().getString(parent.mConfig.warningDialogTitle, label);
174             final String summary = getResources().getString(parent.mConfig.warningDialogSummary,
175                     label);
176             return new AlertDialog.Builder(getContext())
177                     .setMessage(summary)
178                     .setTitle(title)
179                     .setCancelable(true)
180                     .setPositiveButton(R.string.allow,
181                             new DialogInterface.OnClickListener() {
182                                 public void onClick(DialogInterface dialog, int id) {
183                                     parent.mServiceListing.setEnabled(cn, true);
184                                 }
185                             })
186                     .setNegativeButton(R.string.deny,
187                             new DialogInterface.OnClickListener() {
188                                 public void onClick(DialogInterface dialog, int id) {
189                                     // pass
190                                 }
191                             })
192                     .create();
193         }
194     }
195 
196     public static class Config {
197         public String tag;
198         public String setting;
199         public String secondarySetting;
200         public String intentAction;
201         public String permission;
202         public String noun;
203         public int warningDialogTitle;
204         public int warningDialogSummary;
205         public int emptyText;
206     }
207 }
208