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