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.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 
     59     abstract protected Config getConfig();
     60 
     61     public ManagedServiceSettings() {
     62         mConfig = getConfig();
     63     }
     64 
     65     @Override
     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
     85     public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
     86         super.onViewCreated(view, savedInstanceState);
     87         setEmptyText(mConfig.emptyText);
     88     }
     89 
     90     @Override
     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
    102     public void onPause() {
    103         super.onPause();
    104         mServiceListing.setListening(false);
    105     }
    106 
    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 
    152     private int getCurrentUser(int managedProfileId) {
    153         if (managedProfileId != UserHandle.USER_NULL) {
    154             return managedProfileId;
    155         }
    156         return UserHandle.myUserId();
    157     }
    158 
    159     protected boolean isServiceEnabled(ComponentName cn) {
    160         return mServiceListing.isEnabled(cn);
    161     }
    162 
    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 
    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
    189         public int getMetricsCategory() {
    190             return MetricsProto.MetricsEvent.DIALOG_SERVICE_ACCESS_WARNING;
    191         }
    192 
    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
    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 
    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 
    260             public Builder setTag(String tag) {
    261                 mTag = tag;
    262                 return this;
    263             }
    264 
    265             public Builder setSetting(String setting) {
    266                 mSetting = setting;
    267                 return this;
    268             }
    269 
    270             public Builder setIntentAction(String intentAction) {
    271                 mIntentAction = intentAction;
    272                 return this;
    273             }
    274 
    275             public Builder setPermission(String permission) {
    276                 mPermission = permission;
    277                 return this;
    278             }
    279 
    280             public Builder setNoun(String noun) {
    281                 mNoun = noun;
    282                 return this;
    283             }
    284 
    285             public Builder setWarningDialogTitle(int warningDialogTitle) {
    286                 mWarningDialogTitle = warningDialogTitle;
    287                 return this;
    288             }
    289 
    290             public Builder setWarningDialogSummary(int warningDialogSummary) {
    291                 mWarningDialogSummary = warningDialogSummary;
    292                 return this;
    293             }
    294 
    295             public Builder setEmptyText(int emptyText) {
    296                 mEmptyText = emptyText;
    297                 return this;
    298             }
    299 
    300             public Config build() {
    301                 return new Config(mTag, mSetting, mIntentAction, mPermission, mNoun,
    302                         mWarningDialogTitle, mWarningDialogSummary, mEmptyText);
    303             }
    304         }
    305     }
    306 
    307 }
    308