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.support.v14.preference.PreferenceFragment;
     29 import android.support.v14.preference.SwitchPreference;
     30 import android.support.v7.preference.PreferenceScreen;
     31 import android.support.v7.preference.PreferenceViewHolder;
     32 import android.util.ArrayMap;
     33 import android.util.ArraySet;
     34 import android.view.View;
     35 
     36 import com.android.systemui.R;
     37 import com.android.systemui.plugins.PluginInstanceManager;
     38 import com.android.systemui.plugins.PluginManager;
     39 import com.android.systemui.plugins.PluginPrefs;
     40 
     41 import java.util.ArrayList;
     42 import java.util.List;
     43 import java.util.Set;
     44 
     45 public class PluginFragment extends PreferenceFragment {
     46 
     47     public static final String ACTION_PLUGIN_SETTINGS
     48             = "com.android.systemui.action.PLUGIN_SETTINGS";
     49 
     50     private PluginPrefs mPluginPrefs;
     51 
     52     @Override
     53     public void onCreate(Bundle savedInstanceState) {
     54         super.onCreate(savedInstanceState);
     55         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
     56         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
     57         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
     58         filter.addDataScheme("package");
     59         getContext().registerReceiver(mReceiver, filter);
     60         filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
     61         getContext().registerReceiver(mReceiver, filter);
     62     }
     63 
     64     @Override
     65     public void onDestroy() {
     66         super.onDestroy();
     67         getContext().unregisterReceiver(mReceiver);
     68     }
     69 
     70     @Override
     71     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
     72         loadPrefs();
     73     }
     74 
     75     private void loadPrefs() {
     76         PreferenceScreen screen = getPreferenceManager().createPreferenceScreen(getContext());
     77         screen.setOrderingAsAdded(false);
     78         Context prefContext = getPreferenceManager().getContext();
     79         mPluginPrefs = new PluginPrefs(getContext());
     80         PackageManager pm = getContext().getPackageManager();
     81 
     82         Set<String> pluginActions = mPluginPrefs.getPluginList();
     83         ArrayMap<String, ArraySet<String>> plugins = new ArrayMap<>();
     84         for (String action : pluginActions) {
     85             String name = toName(action);
     86             List<ResolveInfo> result = pm.queryIntentServices(
     87                     new Intent(action), PackageManager.MATCH_DISABLED_COMPONENTS);
     88             for (ResolveInfo info : result) {
     89                 String packageName = info.serviceInfo.packageName;
     90                 if (!plugins.containsKey(packageName)) {
     91                     plugins.put(packageName, new ArraySet<>());
     92                 }
     93                 plugins.get(packageName).add(name);
     94             }
     95         }
     96 
     97         List<PackageInfo> apps = pm.getPackagesHoldingPermissions(new String[]{
     98                 PluginInstanceManager.PLUGIN_PERMISSION},
     99                 PackageManager.MATCH_DISABLED_COMPONENTS | PackageManager.GET_SERVICES);
    100         apps.forEach(app -> {
    101             if (!plugins.containsKey(app.packageName)) return;
    102             SwitchPreference pref = new PluginPreference(prefContext, app);
    103             pref.setSummary("Plugins: " + toString(plugins.get(app.packageName)));
    104             screen.addPreference(pref);
    105         });
    106         setPreferenceScreen(screen);
    107     }
    108 
    109     private String toString(ArraySet<String> plugins) {
    110         StringBuilder b = new StringBuilder();
    111         for (String string : plugins) {
    112             if (b.length() != 0) {
    113                 b.append(", ");
    114             }
    115             b.append(string);
    116         }
    117         return b.toString();
    118     }
    119 
    120     private String toName(String action) {
    121         String str = action.replace("com.android.systemui.action.PLUGIN_", "");
    122         StringBuilder b = new StringBuilder();
    123         for (String s : str.split("_")) {
    124             if (b.length() != 0) {
    125                 b.append(' ');
    126             }
    127             b.append(s.substring(0, 1));
    128             b.append(s.substring(1).toLowerCase());
    129         }
    130         return b.toString();
    131     }
    132 
    133     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
    134         @Override
    135         public void onReceive(Context context, Intent intent) {
    136             loadPrefs();
    137         }
    138     };
    139 
    140     private static class PluginPreference extends SwitchPreference {
    141         private final boolean mHasSettings;
    142         private final PackageInfo mInfo;
    143         private final PackageManager mPm;
    144 
    145         public PluginPreference(Context prefContext, PackageInfo info) {
    146             super(prefContext);
    147             mPm = prefContext.getPackageManager();
    148             mHasSettings = mPm.resolveActivity(new Intent(ACTION_PLUGIN_SETTINGS)
    149                     .setPackage(info.packageName), 0) != null;
    150             mInfo = info;
    151             setTitle(info.applicationInfo.loadLabel(mPm));
    152             setChecked(isPluginEnabled());
    153             setWidgetLayoutResource(R.layout.tuner_widget_settings_switch);
    154         }
    155 
    156         private boolean isPluginEnabled() {
    157             for (int i = 0; i < mInfo.services.length; i++) {
    158                 ComponentName componentName = new ComponentName(mInfo.packageName,
    159                         mInfo.services[i].name);
    160                 if (mPm.getComponentEnabledSetting(componentName)
    161                         == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
    162                     return false;
    163                 }
    164             }
    165             return true;
    166         }
    167 
    168         @Override
    169         protected boolean persistBoolean(boolean value) {
    170             final int desiredState = value ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
    171                     : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
    172             for (int i = 0; i < mInfo.services.length; i++) {
    173                 ComponentName componentName = new ComponentName(mInfo.packageName,
    174                         mInfo.services[i].name);
    175                 mPm.setComponentEnabledSetting(componentName, desiredState,
    176                         PackageManager.DONT_KILL_APP);
    177             }
    178             final String pkg = mInfo.packageName;
    179             final Intent intent = new Intent(PluginManager.PLUGIN_CHANGED,
    180                     pkg != null ? Uri.fromParts("package", pkg, null) : null);
    181             getContext().sendBroadcast(intent);
    182             return true;
    183         }
    184 
    185         @Override
    186         public void onBindViewHolder(PreferenceViewHolder holder) {
    187             super.onBindViewHolder(holder);
    188             holder.findViewById(R.id.settings).setVisibility(mHasSettings ? View.VISIBLE
    189                     : View.GONE);
    190             holder.findViewById(R.id.divider).setVisibility(mHasSettings ? View.VISIBLE
    191                     : View.GONE);
    192             holder.findViewById(R.id.settings).setOnClickListener(v -> {
    193                 ResolveInfo result = v.getContext().getPackageManager().resolveActivity(
    194                         new Intent(ACTION_PLUGIN_SETTINGS).setPackage(
    195                                 mInfo.packageName), 0);
    196                 if (result != null) {
    197                     v.getContext().startActivity(new Intent().setComponent(
    198                             new ComponentName(result.activityInfo.packageName,
    199                                     result.activityInfo.name)));
    200                 }
    201             });
    202             holder.itemView.setOnLongClickListener(v -> {
    203                 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    204                 intent.setData(Uri.fromParts("package", mInfo.packageName, null));
    205                 getContext().startActivity(intent);
    206                 return true;
    207             });
    208         }
    209     }
    210 }
    211