Home | History | Annotate | Download | only in tuner
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
      5  * except in compliance with the License. You may obtain a copy of the License at
      6  *
      7  *      http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the
     10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
     11  * KIND, either express or implied. See the License for the specific language governing
     12  * permissions and limitations under the License.
     13  */
     14 
     15 package com.android.systemui.tuner;
     16 
     17 import android.content.BroadcastReceiver;
     18 import android.content.ComponentName;
     19 import android.content.Context;
     20 import android.content.Intent;
     21 import android.content.IntentFilter;
     22 import android.content.pm.PackageInfo;
     23 import android.content.pm.PackageManager;
     24 import android.content.pm.ResolveInfo;
     25 import android.net.Uri;
     26 import android.os.Bundle;
     27 import android.provider.Settings;
     28 import android.util.ArrayMap;
     29 import android.util.ArraySet;
     30 import android.view.View;
     31 
     32 import androidx.preference.PreferenceFragment;
     33 import androidx.preference.PreferenceScreen;
     34 import androidx.preference.PreferenceViewHolder;
     35 import androidx.preference.SwitchPreference;
     36 
     37 import com.android.internal.util.ArrayUtils;
     38 import com.android.systemui.Dependency;
     39 import com.android.systemui.R;
     40 import com.android.systemui.plugins.PluginEnablerImpl;
     41 import com.android.systemui.shared.plugins.PluginEnabler;
     42 import com.android.systemui.shared.plugins.PluginInstanceManager;
     43 import com.android.systemui.shared.plugins.PluginManager;
     44 import com.android.systemui.shared.plugins.PluginPrefs;
     45 
     46 import java.util.List;
     47 import java.util.Set;
     48 
     49 public class PluginFragment extends PreferenceFragment {
     50 
     51     public static final String ACTION_PLUGIN_SETTINGS
     52             = "com.android.systemui.action.PLUGIN_SETTINGS";
     53 
     54     private PluginPrefs mPluginPrefs;
     55     private PluginEnabler mPluginEnabler;
     56 
     57     @Override
     58     public void onCreate(Bundle savedInstanceState) {
     59         super.onCreate(savedInstanceState);
     60         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
     61         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
     62         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
     63         filter.addDataScheme("package");
     64         getContext().registerReceiver(mReceiver, filter);
     65         filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
     66         getContext().registerReceiver(mReceiver, filter);
     67     }
     68 
     69     @Override
     70     public void onDestroy() {
     71         super.onDestroy();
     72         getContext().unregisterReceiver(mReceiver);
     73     }
     74 
     75     @Override
     76     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
     77         mPluginEnabler = new PluginEnablerImpl(getContext());
     78         loadPrefs();
     79     }
     80 
     81     private void loadPrefs() {
     82         PluginManager manager = Dependency.get(PluginManager.class);
     83         PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getContext());
     84         screen.setOrderingAsAdded(false);
     85         Context prefContext = getPreferenceManager().getContext();
     86         mPluginPrefs = new PluginPrefs(getContext());
     87         PackageManager pm = getContext().getPackageManager();
     88 
     89         Set<String> pluginActions = mPluginPrefs.getPluginList();
     90         ArrayMap<String, ArraySet<String>> plugins = new ArrayMap<>();
     91         for (String action : pluginActions) {
     92             String name = toName(action);
     93             List<ResolveInfo> result = pm.queryIntentServices(
     94                     new Intent(action), PackageManager.MATCH_DISABLED_COMPONENTS);
     95             for (ResolveInfo info : result) {
     96                 String packageName = info.serviceInfo.packageName;
     97                 if (!plugins.containsKey(packageName)) {
     98                     plugins.put(packageName, new ArraySet<>());
     99                 }
    100                 plugins.get(packageName).add(name);
    101             }
    102         }
    103 
    104         List<PackageInfo> apps = pm.getPackagesHoldingPermissions(new String[]{
    105                 PluginInstanceManager.PLUGIN_PERMISSION},
    106                 PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_SERVICES);
    107         apps.forEach(app -> {
    108             if (!plugins.containsKey(app.packageName)) return;
    109             if (ArrayUtils.contains(manager.getWhitelistedPlugins(), app.packageName)) {
    110                 // Don't manage whitelisted plugins, they are part of the OS.
    111                 return;
    112             }
    113             SwitchPreference pref = new PluginPreference(prefContext, app, mPluginEnabler);
    114             pref.setSummary("Plugins: " + toString(plugins.get(app.packageName)));
    115             screen.addPreference(pref);
    116         });
    117         setPreferenceScreen(screen);
    118     }
    119 
    120     private String toString(ArraySet<String> plugins) {
    121         StringBuilder b = new StringBuilder();
    122         for (String string : plugins) {
    123             if (b.length() != 0) {
    124                 b.append(", ");
    125             }
    126             b.append(string);
    127         }
    128         return b.toString();
    129     }
    130 
    131     private String toName(String action) {
    132         String str = action.replace("com.android.systemui.action.PLUGIN_", "");
    133         StringBuilder b = new StringBuilder();
    134         for (String s : str.split("_")) {
    135             if (b.length() != 0) {
    136                 b.append(' ');
    137             }
    138             b.append(s.substring(0, 1));
    139             b.append(s.substring(1).toLowerCase());
    140         }
    141         return b.toString();
    142     }
    143 
    144     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    145         @Override
    146         public void onReceive(Context context, Intent intent) {
    147             loadPrefs();
    148         }
    149     };
    150 
    151     private static class PluginPreference extends SwitchPreference {
    152         private final boolean mHasSettings;
    153         private final PackageInfo mInfo;
    154         private final PluginEnabler mPluginEnabler;
    155 
    156         public PluginPreference(Context prefContext, PackageInfo info, PluginEnabler pluginEnabler) {
    157             super(prefContext);
    158             PackageManager pm = prefContext.getPackageManager();
    159             mHasSettings = pm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS)
    160                     .setPackage(info.packageName), 0) != null;
    161             mInfo = info;
    162             mPluginEnabler = pluginEnabler;
    163             setTitle(info.applicationInfo.loadLabel(pm));
    164             setChecked(isPluginEnabled());
    165             setWidgetLayoutResource(R.layout.tuner_widget_settings_switch);
    166         }
    167 
    168         private boolean isPluginEnabled() {
    169             for (int i = 0; i < mInfo.services.length; i++) {
    170                 ComponentName componentName = new ComponentName(mInfo.packageName,
    171                         mInfo.services[i].name);
    172                 if (!mPluginEnabler.isEnabled(componentName)) {
    173                     return false;
    174                 }
    175             }
    176             return true;
    177         }
    178 
    179         @Override
    180         protected boolean persistBoolean(boolean isEnabled) {
    181             boolean shouldSendBroadcast = false;
    182             for (int i = 0; i < mInfo.services.length; i++) {
    183                 ComponentName componentName = new ComponentName(mInfo.packageName,
    184                         mInfo.services[i].name);
    185 
    186                 if (mPluginEnabler.isEnabled(componentName) != isEnabled) {
    187                     if (isEnabled) {
    188                         mPluginEnabler.setEnabled(componentName);
    189                     } else {
    190                         mPluginEnabler.setDisabled(componentName, PluginEnabler.DISABLED_MANUALLY);
    191                     }
    192                     shouldSendBroadcast = true;
    193                 }
    194             }
    195             if (shouldSendBroadcast) {
    196                 final String pkg = mInfo.packageName;
    197                 final Intent intent = new Intent(PluginManager.PLUGIN_CHANGED,
    198                         pkg != null ? Uri.fromParts("package", pkg, null) : null);
    199                 getContext().sendBroadcast(intent);
    200             }
    201             return true;
    202         }
    203 
    204         @Override
    205         public void onBindViewHolder(PreferenceViewHolder holder) {
    206             super.onBindViewHolder(holder);
    207             holder.findViewById(R.id.settings).setVisibility(mHasSettings ? View.VISIBLE
    208                     : View.GONE);
    209             holder.findViewById(R.id.divider).setVisibility(mHasSettings ? View.VISIBLE
    210                     : View.GONE);
    211             holder.findViewById(R.id.settings).setOnClickListener(v -> {
    212                 ResolveInfo result = v.getContext().getPackageManager().resolveActivity(
    213                         new Intent(ACTION_PLUGIN_SETTINGS).setPackage(
    214                                 mInfo.packageName), 0);
    215                 if (result != null) {
    216                     v.getContext().startActivity(new Intent().setComponent(
    217                             new ComponentName(result.activityInfo.packageName,
    218                                     result.activityInfo.name)));
    219                 }
    220             });
    221             holder.itemView.setOnLongClickListener(v -> {
    222                 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    223                 intent.setData(Uri.fromParts("package", mInfo.packageName, null));
    224                 getContext().startActivity(intent);
    225                 return true;
    226             });
    227         }
    228     }
    229 }
    230