• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 import androidx.annotation.VisibleForTesting;
28 import androidx.preference.Preference;
29 
30 import com.android.settings.core.PreferenceControllerMixin;
31 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
32 import com.android.settingslib.RestrictedLockUtilsInternal;
33 import com.android.settingslib.RestrictedSwitchPreference;
34 import com.android.settingslib.development.DeveloperOptionsPreferenceController;
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 DeveloperOptionsPreferenceController
42         implements Preference.OnPreferenceChangeListener, AdbOnChangeListener,
43         PreferenceControllerMixin {
44     private static final String VERIFY_APPS_OVER_USB_KEY = "verify_apps_over_usb";
45     private static final String PACKAGE_MIME_TYPE = "application/vnd.android.package-archive";
46 
47     @VisibleForTesting
48     static final int SETTING_VALUE_ON = 1;
49     @VisibleForTesting
50     static final int SETTING_VALUE_OFF = 0;
51 
52     /**
53      * Class for indirection of RestrictedLockUtils for testing purposes. It would be nice to mock
54      * the appropriate methods in UserManager instead but they aren't accessible.
55      */
56     @VisibleForTesting
57     class RestrictedLockUtilsDelegate {
checkIfRestrictionEnforced( Context context, String userRestriction, int userId)58         public EnforcedAdmin checkIfRestrictionEnforced(
59                 Context context, String userRestriction, int userId) {
60             return RestrictedLockUtilsInternal.checkIfRestrictionEnforced(context, userRestriction,
61                     userId);
62         }
63     }
64 
65     // NB: This field is accessed using reflection in the test, please keep name in sync.
66     private final RestrictedLockUtilsDelegate mRestrictedLockUtils =
67             new RestrictedLockUtilsDelegate();
68 
69     // This field is accessed using reflection in the test, please keep name in sync.
70     private final PackageManager mPackageManager;
71 
VerifyAppsOverUsbPreferenceController(Context context)72     public VerifyAppsOverUsbPreferenceController(Context context) {
73         super(context);
74 
75         mPackageManager = context.getPackageManager();
76     }
77 
78     @Override
isAvailable()79     public boolean isAvailable() {
80         return Settings.Global.getInt(mContext.getContentResolver(),
81                 Settings.Global.PACKAGE_VERIFIER_SETTING_VISIBLE, 1 /* default */) > 0;
82     }
83 
84     @Override
getPreferenceKey()85     public String getPreferenceKey() {
86         return VERIFY_APPS_OVER_USB_KEY;
87     }
88 
89     @Override
onPreferenceChange(Preference preference, Object newValue)90     public boolean onPreferenceChange(Preference preference, Object newValue) {
91         final boolean isEnabled = (Boolean) newValue;
92         Settings.Global.putInt(mContext.getContentResolver(),
93                 Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB,
94                 isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF);
95         return true;
96     }
97 
98     @Override
updateState(Preference preference)99     public void updateState(Preference preference) {
100         final RestrictedSwitchPreference restrictedPreference =
101             (RestrictedSwitchPreference) preference;
102         if (!shouldBeEnabled()) {
103             restrictedPreference.setChecked(false);
104             restrictedPreference.setDisabledByAdmin(null);
105             restrictedPreference.setEnabled(false);
106             return;
107         }
108 
109         final EnforcedAdmin enforcingAdmin = mRestrictedLockUtils.checkIfRestrictionEnforced(
110                 mContext, UserManager.ENSURE_VERIFY_APPS, UserHandle.myUserId());
111         if (enforcingAdmin != null) {
112             restrictedPreference.setChecked(true);
113             restrictedPreference.setDisabledByAdmin(enforcingAdmin);
114             return;
115         }
116 
117         restrictedPreference.setEnabled(true);
118         final boolean checked = Settings.Global.getInt(mContext.getContentResolver(),
119                 Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, SETTING_VALUE_ON)
120                 != SETTING_VALUE_OFF;
121         restrictedPreference.setChecked(checked);
122     }
123 
124     @Override
onAdbSettingChanged()125     public void onAdbSettingChanged() {
126         if (isAvailable()) {
127             updateState(mPreference);
128         }
129     }
130 
131     @Override
onDeveloperOptionsSwitchEnabled()132     protected void onDeveloperOptionsSwitchEnabled() {
133         super.onDeveloperOptionsSwitchEnabled();
134         updateState(mPreference);
135     }
136 
137     /**
138      * Checks whether the toggle should be enabled depending on whether verify apps over USB is
139      * possible currently. If ADB is disabled or if package verifier does not exist, the toggle
140      * should be disabled.
141      */
shouldBeEnabled()142     private boolean shouldBeEnabled() {
143         final ContentResolver cr = mContext.getContentResolver();
144         if (Settings.Global.getInt(cr, Settings.Global.ADB_ENABLED,
145                 AdbPreferenceController.ADB_SETTING_OFF)
146                 == AdbPreferenceController.ADB_SETTING_OFF) {
147             return false;
148         }
149         if (Settings.Global.getInt(cr, Settings.Global.PACKAGE_VERIFIER_ENABLE, SETTING_VALUE_ON)
150                 == SETTING_VALUE_OFF) {
151             return false;
152         } else {
153             final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION);
154             verification.setType(PACKAGE_MIME_TYPE);
155             verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
156             final List<ResolveInfo> receivers = mPackageManager.queryBroadcastReceivers(
157                     verification, 0 /* flags */);
158             if (receivers.size() == 0) {
159                 return false;
160             }
161         }
162         return true;
163     }
164 }
165