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