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