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 
17 package com.android.settings.vpn2;
18 
19 import android.app.admin.DevicePolicyManager;
20 import android.content.Context;
21 import android.content.pm.PackageInfo;
22 import android.content.pm.PackageManager;
23 import android.graphics.drawable.Drawable;
24 import android.os.UserHandle;
25 
26 import androidx.preference.Preference;
27 
28 import com.android.internal.net.LegacyVpnInfo;
29 import com.android.internal.net.VpnConfig;
30 import com.android.settingslib.RestrictedLockUtils;
31 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
32 import com.android.settings.R;
33 
34 /**
35  * {@link androidx.preference.Preference} containing information about a VPN
36  * application. Tracks the package name and connection state.
37  */
38 public class AppPreference extends ManageablePreference {
39     public static final int STATE_CONNECTED = LegacyVpnInfo.STATE_CONNECTED;
40     public static final int STATE_DISCONNECTED = STATE_NONE;
41 
42     private final String mPackageName;
43     private final String mName;
44 
AppPreference(Context context, int userId, String packageName)45     public AppPreference(Context context, int userId, String packageName) {
46         super(context, null /* attrs */, R.style.VpnAppManagementPreferenceStyle, 0);
47         super.setUserId(userId);
48 
49         mPackageName = packageName;
50         disableIfConfiguredByAdmin();
51 
52         // Fetch icon and VPN label
53         String label = packageName;
54         Drawable icon = null;
55         try {
56             // Make all calls to the package manager as the appropriate user.
57             Context userContext = getUserContext();
58             PackageManager pm = userContext.getPackageManager();
59             // The nested catch block is for the case that the app doesn't exist, so we can fall
60             // back to the default activity icon.
61             try {
62                 PackageInfo pkgInfo = pm.getPackageInfo(mPackageName, 0 /* flags */);
63                 if (pkgInfo != null) {
64                     icon = pkgInfo.applicationInfo.loadIcon(pm);
65                     label = VpnConfig.getVpnLabel(userContext, mPackageName).toString();
66                 }
67             } catch (PackageManager.NameNotFoundException pkgNotFound) {
68                 // Use default app label and icon as fallback
69             }
70             if (icon == null) {
71                 icon = pm.getDefaultActivityIcon();
72             }
73         } catch (PackageManager.NameNotFoundException userNotFound) {
74             // No user, no useful information to obtain. Quietly fail.
75         }
76         mName = label;
77 
78         setTitle(mName);
79         setIcon(icon);
80     }
81 
82     /**
83      * Disable this preference if VPN is set as always on by a profile or device owner.
84      * NB: it should be called after super.setUserId() otherwise admin information can be lost.
85      */
disableIfConfiguredByAdmin()86     private void disableIfConfiguredByAdmin() {
87         if (isDisabledByAdmin()) {
88             // Already disabled due to user restriction.
89             return;
90         }
91         final DevicePolicyManager dpm = getContext()
92                 .createContextAsUser(UserHandle.of(getUserId()), /* flags= */ 0)
93                 .getSystemService(DevicePolicyManager.class);
94         if (mPackageName.equals(dpm.getAlwaysOnVpnPackage())) {
95             final EnforcedAdmin admin = RestrictedLockUtils.getProfileOrDeviceOwner(
96                     getContext(), UserHandle.of(mUserId));
97             setDisabledByAdmin(admin);
98         }
99     }
100 
getPackageInfo()101     public PackageInfo getPackageInfo() {
102         try {
103             PackageManager pm = getUserContext().getPackageManager();
104             return pm.getPackageInfo(mPackageName, 0 /* flags */);
105         } catch (PackageManager.NameNotFoundException nnfe) {
106             return null;
107         }
108     }
109 
getLabel()110     public String getLabel() {
111         return mName;
112     }
113 
getPackageName()114     public String getPackageName() {
115         return mPackageName;
116     }
117 
getUserContext()118     private Context getUserContext() throws PackageManager.NameNotFoundException {
119         UserHandle user = UserHandle.of(mUserId);
120         return getContext().createPackageContextAsUser(
121                 getContext().getPackageName(), 0 /* flags */, user);
122     }
123 
compareTo(Preference preference)124     public int compareTo(Preference preference) {
125         if (preference instanceof AppPreference) {
126             AppPreference another = (AppPreference) preference;
127             int result;
128             if ((result = another.mState - mState) == 0 &&
129                     (result = mName.compareToIgnoreCase(another.mName)) == 0 &&
130                     (result = mPackageName.compareTo(another.mPackageName)) == 0) {
131                 result = mUserId - another.mUserId;
132             }
133             return result;
134         } else if (preference instanceof LegacyVpnPreference) {
135             // Use comparator from ConfigPreference
136             LegacyVpnPreference another = (LegacyVpnPreference) preference;
137             return -another.compareTo(this);
138         } else {
139             return super.compareTo(preference);
140         }
141     }
142 }
143 
144