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.development; 17 18 import android.content.ContentResolver; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.pm.PackageManager; 22 import android.content.pm.ResolveInfo; 23 import android.os.UserHandle; 24 import android.os.UserManager; 25 import android.provider.Settings; 26 import android.support.annotation.VisibleForTesting; 27 import android.support.v7.preference.Preference; 28 import android.support.v7.preference.PreferenceScreen; 29 30 import com.android.settings.core.PreferenceControllerMixin; 31 import com.android.settingslib.RestrictedLockUtils; 32 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; 33 import com.android.settingslib.RestrictedSwitchPreference; 34 import com.android.settingslib.core.AbstractPreferenceController; 35 36 import java.util.List; 37 38 /** 39 * Controller to manage the state of "Verify apps over USB" toggle. 40 */ 41 public class VerifyAppsOverUsbPreferenceController extends AbstractPreferenceController implements 42 PreferenceControllerMixin { 43 private static final String VERIFY_APPS_OVER_USB_KEY = "verify_apps_over_usb"; 44 private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive"; 45 46 private RestrictedSwitchPreference mPreference; 47 48 /** 49 * Class for indirection of RestrictedLockUtils for testing purposes. It would be nice to mock 50 * the appropriate methods in UserManager instead but they aren't accessible. 51 */ 52 @VisibleForTesting 53 class RestrictedLockUtilsDelegate { checkIfRestrictionEnforced( Context context, String userRestriction, int userId)54 public EnforcedAdmin checkIfRestrictionEnforced( 55 Context context, String userRestriction, int userId) { 56 return RestrictedLockUtils.checkIfRestrictionEnforced(context, userRestriction, userId); 57 } 58 } 59 // NB: This field is accessed using reflection in the test, please keep name in sync. 60 private final RestrictedLockUtilsDelegate mRestrictedLockUtils = 61 new RestrictedLockUtilsDelegate(); 62 VerifyAppsOverUsbPreferenceController(Context context)63 VerifyAppsOverUsbPreferenceController(Context context) { 64 super(context); 65 } 66 67 @Override displayPreference(PreferenceScreen screen)68 public void displayPreference(PreferenceScreen screen) { 69 super.displayPreference(screen); 70 if (isAvailable()) { 71 mPreference = (RestrictedSwitchPreference) 72 screen.findPreference(VERIFY_APPS_OVER_USB_KEY); 73 } 74 } 75 76 @Override isAvailable()77 public boolean isAvailable() { 78 return Settings.Global.getInt(mContext.getContentResolver(), 79 Settings.Global.PACKAGE_VERIFIER_SETTING_VISIBLE, 1) > 0; 80 } 81 82 @Override getPreferenceKey()83 public String getPreferenceKey() { 84 return VERIFY_APPS_OVER_USB_KEY; 85 } 86 87 /** Saves the settings value when it is toggled. */ 88 @Override handlePreferenceTreeClick(Preference preference)89 public boolean handlePreferenceTreeClick(Preference preference) { 90 if (VERIFY_APPS_OVER_USB_KEY.equals(preference.getKey())) { 91 Settings.Global.putInt(mContext.getContentResolver(), 92 Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, mPreference.isChecked() ? 1 : 0); 93 return true; 94 } 95 return false; 96 } 97 98 /** 99 * Checks whether the toggle should be enabled depending on whether verify apps over USB is 100 * possible currently. If ADB is disabled or if package verifier does not exist, the toggle 101 * should be disabled. 102 */ shouldBeEnabled()103 private boolean shouldBeEnabled() { 104 final ContentResolver cr = mContext.getContentResolver(); 105 if (Settings.Global.getInt(cr, Settings.Global.ADB_ENABLED, 0) == 0) { 106 return false; 107 } 108 if (Settings.Global.getInt(cr, Settings.Global.PACKAGE_VERIFIER_ENABLE, 1) == 0) { 109 return false; 110 } else { 111 final PackageManager pm = mContext.getPackageManager(); 112 final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); 113 verification.setType(PACKAGE_MIME_TYPE); 114 verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 115 final List<ResolveInfo> receivers = pm.queryBroadcastReceivers(verification, 0); 116 if (receivers.size() == 0) { 117 return false; 118 } 119 } 120 return true; 121 } 122 123 /** 124 * Updates position, enabled status and maybe admin message. 125 */ updatePreference()126 public void updatePreference() { 127 if (!isAvailable()) { 128 return; 129 } 130 131 if (!shouldBeEnabled()) { 132 mPreference.setChecked(false); 133 mPreference.setDisabledByAdmin(null); 134 mPreference.setEnabled(false); 135 return; 136 } 137 138 final EnforcedAdmin enforcingAdmin = mRestrictedLockUtils.checkIfRestrictionEnforced( 139 mContext, UserManager.ENSURE_VERIFY_APPS, UserHandle.myUserId()); 140 if (enforcingAdmin != null) { 141 mPreference.setChecked(true); 142 mPreference.setDisabledByAdmin(enforcingAdmin); 143 return; 144 } 145 146 mPreference.setEnabled(true); 147 final boolean checked = Settings.Global.getInt(mContext.getContentResolver(), 148 Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, 1) != 0; 149 mPreference.setChecked(checked); 150 } 151 } 152