1 /* 2 * Copyright (C) 2017 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 package com.android.settings.applications.appinfo; 17 18 import static android.app.Activity.RESULT_CANCELED; 19 import static android.app.Activity.RESULT_OK; 20 21 import android.app.ActivityManager; 22 import android.app.AppOpsManager; 23 import android.app.settings.SettingsEnums; 24 import android.content.Context; 25 import android.os.Bundle; 26 import android.os.UserHandle; 27 import android.os.UserManager; 28 29 import androidx.appcompat.app.AlertDialog; 30 import androidx.preference.Preference; 31 import androidx.preference.Preference.OnPreferenceChangeListener; 32 33 import com.android.internal.annotations.VisibleForTesting; 34 import com.android.settings.R; 35 import com.android.settings.Settings; 36 import com.android.settings.applications.AppInfoWithHeader; 37 import com.android.settings.applications.AppStateInstallAppsBridge; 38 import com.android.settings.applications.AppStateInstallAppsBridge.InstallAppsState; 39 import com.android.settingslib.RestrictedSwitchPreference; 40 import com.android.settingslib.applications.ApplicationsState.AppEntry; 41 42 public class ExternalSourcesDetails extends AppInfoWithHeader 43 implements OnPreferenceChangeListener { 44 45 private static final String KEY_EXTERNAL_SOURCE_SWITCH = "external_sources_settings_switch"; 46 47 private AppStateInstallAppsBridge mAppBridge; 48 private AppOpsManager mAppOpsManager; 49 private ActivityManager mActivityManager; 50 private UserManager mUserManager; 51 private RestrictedSwitchPreference mSwitchPref; 52 private InstallAppsState mInstallAppsState; 53 54 @Override onCreate(Bundle savedInstanceState)55 public void onCreate(Bundle savedInstanceState) { 56 super.onCreate(savedInstanceState); 57 58 final Context context = getActivity(); 59 mAppBridge = new AppStateInstallAppsBridge(context, mState, null); 60 mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 61 mActivityManager = context.getSystemService(ActivityManager.class); 62 mUserManager = UserManager.get(context); 63 64 addPreferencesFromResource(R.xml.external_sources_details); 65 mSwitchPref = (RestrictedSwitchPreference) findPreference(KEY_EXTERNAL_SOURCE_SWITCH); 66 mSwitchPref.setOnPreferenceChangeListener(this); 67 } 68 69 @Override onPreferenceChange(Preference preference, Object newValue)70 public boolean onPreferenceChange(Preference preference, Object newValue) { 71 final boolean checked = (Boolean) newValue; 72 if (preference == mSwitchPref) { 73 if (mInstallAppsState != null && checked != mInstallAppsState.canInstallApps()) { 74 if (Settings.ManageAppExternalSourcesActivity.class.getName().equals( 75 getIntent().getComponent().getClassName())) { 76 setResult(checked ? RESULT_OK : RESULT_CANCELED); 77 } 78 setCanInstallApps(checked); 79 refreshUi(); 80 } 81 return true; 82 } 83 return false; 84 } 85 getPreferenceSummary(Context context, AppEntry entry)86 public static CharSequence getPreferenceSummary(Context context, AppEntry entry) { 87 final UserHandle userHandle = UserHandle.getUserHandleForUid(entry.info.uid); 88 final UserManager um = UserManager.get(context); 89 final int userRestrictionSource = um.getUserRestrictionSource( 90 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, userHandle) 91 | um.getUserRestrictionSource( 92 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY, 93 userHandle); 94 if ((userRestrictionSource & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) { 95 return context.getString(R.string.disabled_by_admin); 96 } else if (userRestrictionSource != 0) { 97 return context.getString(R.string.disabled); 98 } 99 final InstallAppsState appsState = new AppStateInstallAppsBridge(context, null, null) 100 .createInstallAppsStateFor(entry.info.packageName, entry.info.uid); 101 return context.getString(appsState.canInstallApps() 102 ? R.string.app_permission_summary_allowed 103 : R.string.app_permission_summary_not_allowed); 104 } 105 106 @VisibleForTesting setCanInstallApps(boolean newState)107 void setCanInstallApps(boolean newState) { 108 mAppOpsManager.setMode(AppOpsManager.OP_REQUEST_INSTALL_PACKAGES, 109 mPackageInfo.applicationInfo.uid, mPackageName, 110 newState ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_ERRORED); 111 if (!newState) { 112 killApp(mPackageInfo.applicationInfo.uid); 113 } 114 } 115 killApp(int uid)116 private void killApp(int uid) { 117 if (UserHandle.isCore(uid)) { 118 return; 119 } 120 mActivityManager.killUid(uid, "User denied OP_REQUEST_INSTALL_PACKAGES"); 121 } 122 123 @Override refreshUi()124 protected boolean refreshUi() { 125 if (mPackageInfo == null || mPackageInfo.applicationInfo == null) { 126 return false; 127 } 128 if (mUserManager.hasBaseUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, 129 UserHandle.of(UserHandle.myUserId()))) { 130 mSwitchPref.setChecked(false); 131 mSwitchPref.setSummary(R.string.disabled); 132 mSwitchPref.setEnabled(false); 133 return true; 134 } 135 mSwitchPref.checkRestrictionAndSetDisabled(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); 136 if (!mSwitchPref.isDisabledByAdmin()) { 137 mSwitchPref.checkRestrictionAndSetDisabled( 138 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY); 139 } 140 if (mSwitchPref.isDisabledByAdmin()) { 141 return true; 142 } 143 mInstallAppsState = mAppBridge.createInstallAppsStateFor(mPackageName, 144 mPackageInfo.applicationInfo.uid); 145 if (!mInstallAppsState.isPotentialAppSource()) { 146 // Invalid app entry. Should not allow changing permission 147 mSwitchPref.setEnabled(false); 148 return true; 149 } 150 mSwitchPref.setChecked(mInstallAppsState.canInstallApps()); 151 return true; 152 } 153 154 @Override createDialog(int id, int errorCode)155 protected AlertDialog createDialog(int id, int errorCode) { 156 return null; 157 } 158 159 @Override getMetricsCategory()160 public int getMetricsCategory() { 161 return SettingsEnums.MANAGE_EXTERNAL_SOURCES; 162 } 163 } 164