1/* 2 * Copyright (C) 2015 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 17package com.android.tv.settings.device.apps; 18 19import android.app.ActivityManager; 20import android.content.Context; 21import android.content.pm.PackageInfo; 22import android.content.pm.PackageManager; 23import android.content.pm.ResolveInfo; 24import android.os.Bundle; 25import android.support.annotation.NonNull; 26import android.support.v17.leanback.widget.GuidanceStylist; 27 28import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 29import com.android.settingslib.Utils; 30import com.android.settingslib.applications.ApplicationsState; 31import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; 32import com.android.tv.settings.R; 33 34import java.util.ArrayList; 35import java.util.HashSet; 36import java.util.List; 37 38public class EnableDisablePreference extends AppActionPreference { 39 40 private final PackageManager mPackageManager; 41 42 public EnableDisablePreference(Context context, 43 ApplicationsState.AppEntry entry) { 44 super(context, entry); 45 mPackageManager = context.getPackageManager(); 46 refresh(); 47 } 48 49 public void refresh() { 50 if (!UninstallPreference.canUninstall(mEntry) && canDisable()) { 51 setVisible(true); 52 if (mEntry.info.enabled) { 53 setTitle(R.string.device_apps_app_management_disable); 54 ConfirmationFragment.prepareArgs(getExtras(), mEntry.info.packageName, false); 55 } else { 56 setTitle(R.string.device_apps_app_management_enable); 57 ConfirmationFragment.prepareArgs(getExtras(), mEntry.info.packageName, true); 58 } 59 } else { 60 setVisible(false); 61 } 62 } 63 64 private boolean canDisable() { 65 final HashSet<String> homePackages = getHomePackages(); 66 PackageInfo packageInfo; 67 try { 68 packageInfo = mPackageManager.getPackageInfo(mEntry.info.packageName, 69 PackageManager.GET_DISABLED_COMPONENTS | 70 PackageManager.GET_UNINSTALLED_PACKAGES | 71 PackageManager.GET_SIGNATURES); 72 } catch (PackageManager.NameNotFoundException e) { 73 return false; 74 } 75 return !(homePackages.contains(mEntry.info.packageName) || 76 Utils.isSystemPackage(getContext().getResources(), mPackageManager, packageInfo)); 77 } 78 79 private HashSet<String> getHomePackages() { 80 HashSet<String> homePackages = new HashSet<>(); 81 // Get list of "home" apps and trace through any meta-data references 82 List<ResolveInfo> homeActivities = new ArrayList<>(); 83 mPackageManager.getHomeActivities(homeActivities); 84 for (ResolveInfo ri : homeActivities) { 85 final String activityPkg = ri.activityInfo.packageName; 86 homePackages.add(activityPkg); 87 // Also make sure to include anything proxying for the home app 88 final Bundle metadata = ri.activityInfo.metaData; 89 if (metadata != null) { 90 final String metaPkg = metadata.getString(ActivityManager.META_HOME_ALTERNATE); 91 if (signaturesMatch(mPackageManager, metaPkg, activityPkg)) { 92 homePackages.add(metaPkg); 93 } 94 } 95 } 96 return homePackages; 97 } 98 99 private static boolean signaturesMatch(PackageManager pm, String pkg1, String pkg2) { 100 if (pkg1 != null && pkg2 != null) { 101 try { 102 final int match = pm.checkSignatures(pkg1, pkg2); 103 if (match >= PackageManager.SIGNATURE_MATCH) { 104 return true; 105 } 106 } catch (Exception e) { 107 // e.g. named alternate package not found during lookup; 108 // this is an expected case sometimes 109 } 110 } 111 return false; 112 } 113 114 @Override 115 public String getFragment() { 116 return ConfirmationFragment.class.getName(); 117 } 118 119 public static class ConfirmationFragment extends AppActionPreference.ConfirmationFragment { 120 private static final String ARG_PACKAGE_NAME = "packageName"; 121 private static final String ARG_ENABLE = "enable"; 122 123 private static void prepareArgs(@NonNull Bundle args, String packageName, boolean enable) { 124 args.putString(ARG_PACKAGE_NAME, packageName); 125 args.putBoolean(ARG_ENABLE, enable); 126 } 127 128 private final MetricsFeatureProvider mMetricsFeatureProvider = new MetricsFeatureProvider(); 129 130 @NonNull 131 @Override 132 public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) { 133 final AppManagementFragment fragment = (AppManagementFragment) getTargetFragment(); 134 final Boolean enable = getArguments().getBoolean(ARG_ENABLE); 135 return new GuidanceStylist.Guidance( 136 getString(enable ? R.string.device_apps_app_management_enable : 137 R.string.device_apps_app_management_disable), 138 getString(enable ? R.string.device_apps_app_management_enable_desc : 139 R.string.device_apps_app_management_disable_desc), 140 fragment.getAppName(), 141 fragment.getAppIcon()); 142 } 143 144 @Override 145 public void onOk() { 146 boolean enable = getArguments().getBoolean(ARG_ENABLE); 147 mMetricsFeatureProvider.action(getContext(), enable 148 ? MetricsEvent.ACTION_SETTINGS_ENABLE_APP 149 : MetricsEvent.ACTION_SETTINGS_DISABLE_APP); 150 getActivity().getPackageManager().setApplicationEnabledSetting( 151 getArguments().getString(ARG_PACKAGE_NAME), enable 152 ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT 153 : PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 154 0); 155 } 156 } 157} 158