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.Dialog; 20 import android.app.admin.DevicePolicyManager; 21 import android.app.settings.SettingsEnums; 22 import android.content.Context; 23 import android.content.DialogInterface; 24 import android.content.pm.PackageInfo; 25 import android.net.IConnectivityManager; 26 import android.net.VpnManager; 27 import android.os.Bundle; 28 import android.os.RemoteException; 29 import android.os.ServiceManager; 30 import android.os.UserHandle; 31 import android.os.UserManager; 32 import android.util.Log; 33 34 import androidx.appcompat.app.AlertDialog; 35 import androidx.fragment.app.Fragment; 36 37 import com.android.internal.net.VpnConfig; 38 import com.android.settings.R; 39 import com.android.settings.core.instrumentation.InstrumentedDialogFragment; 40 41 /** 42 * Fragment wrapper around an {@link AppDialog}. 43 */ 44 public class AppDialogFragment extends InstrumentedDialogFragment implements AppDialog.Listener { 45 private static final String TAG_APP_DIALOG = "vpnappdialog"; 46 private static final String TAG = "AppDialogFragment"; 47 48 private static final String ARG_MANAGING = "managing"; 49 private static final String ARG_LABEL = "label"; 50 private static final String ARG_CONNECTED = "connected"; 51 private static final String ARG_PACKAGE = "package"; 52 53 private PackageInfo mPackageInfo; 54 private Listener mListener; 55 56 private UserManager mUserManager; 57 private final IConnectivityManager mService = IConnectivityManager.Stub.asInterface( 58 ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); 59 private DevicePolicyManager mDevicePolicyManager; 60 61 @Override getMetricsCategory()62 public int getMetricsCategory() { 63 return SettingsEnums.DIALOG_VPN_APP_CONFIG; 64 } 65 66 public interface Listener { onForget()67 void onForget(); onCancel()68 void onCancel(); 69 } 70 show(Fragment parent, PackageInfo packageInfo, String label, boolean managing, boolean connected)71 public static void show(Fragment parent, PackageInfo packageInfo, String label, 72 boolean managing, boolean connected) { 73 if (!managing && !connected) { 74 // We can't display anything useful for this case. 75 return; 76 } 77 show(parent, null, packageInfo, label, managing, connected); 78 } 79 show(Fragment parent, Listener listener, PackageInfo packageInfo, String label, boolean managing, boolean connected)80 public static void show(Fragment parent, Listener listener, PackageInfo packageInfo, 81 String label, boolean managing, boolean connected) { 82 if (!parent.isAdded()) { 83 return; 84 } 85 86 Bundle args = new Bundle(); 87 args.putParcelable(ARG_PACKAGE, packageInfo); 88 args.putString(ARG_LABEL, label); 89 args.putBoolean(ARG_MANAGING, managing); 90 args.putBoolean(ARG_CONNECTED, connected); 91 92 final AppDialogFragment frag = new AppDialogFragment(); 93 frag.mListener = listener; 94 frag.setArguments(args); 95 frag.setTargetFragment(parent, 0); 96 frag.show(parent.getFragmentManager(), TAG_APP_DIALOG); 97 } 98 99 @Override onCreate(Bundle savedInstanceState)100 public void onCreate(Bundle savedInstanceState) { 101 super.onCreate(savedInstanceState); 102 mPackageInfo = getArguments().getParcelable(ARG_PACKAGE); 103 mUserManager = UserManager.get(getContext()); 104 mDevicePolicyManager = getContext() 105 .createContextAsUser(UserHandle.of(getUserId()), /* flags= */ 0) 106 .getSystemService(DevicePolicyManager.class); 107 } 108 109 @Override onCreateDialog(Bundle savedInstanceState)110 public Dialog onCreateDialog(Bundle savedInstanceState) { 111 Bundle args = getArguments(); 112 final String label = args.getString(ARG_LABEL); 113 boolean managing = args.getBoolean(ARG_MANAGING); 114 boolean connected = args.getBoolean(ARG_CONNECTED); 115 116 if (managing) { 117 return new AppDialog(getActivity(), this, mPackageInfo, label); 118 } else { 119 // Build an AlertDialog with an option to disconnect. 120 AlertDialog.Builder dlog = new AlertDialog.Builder(getActivity()) 121 .setTitle(label) 122 .setMessage(getActivity().getString(R.string.vpn_disconnect_confirm)) 123 .setNegativeButton(getActivity().getString(R.string.vpn_cancel), null); 124 125 if (connected && !isUiRestricted()) { 126 dlog.setPositiveButton(getActivity().getString(R.string.vpn_disconnect), 127 new DialogInterface.OnClickListener() { 128 @Override 129 public void onClick(DialogInterface dialog, int which) { 130 onDisconnect(dialog); 131 } 132 }); 133 } 134 return dlog.create(); 135 } 136 } 137 138 @Override onCancel(DialogInterface dialog)139 public void onCancel(DialogInterface dialog) { 140 dismiss(); 141 if (mListener != null) { 142 mListener.onCancel(); 143 } 144 super.onCancel(dialog); 145 } 146 147 @Override onForget(final DialogInterface dialog)148 public void onForget(final DialogInterface dialog) { 149 if (isUiRestricted()) { 150 return; 151 } 152 final int userId = getUserId(); 153 try { 154 mService.setVpnPackageAuthorization( 155 mPackageInfo.packageName, userId, VpnManager.TYPE_VPN_NONE); 156 onDisconnect(dialog); 157 } catch (RemoteException e) { 158 Log.e(TAG, "Failed to forget authorization of " + mPackageInfo.packageName + 159 " for user " + userId, e); 160 } 161 162 if (mListener != null) { 163 mListener.onForget(); 164 } 165 } 166 onDisconnect(final DialogInterface dialog)167 private void onDisconnect(final DialogInterface dialog) { 168 if (isUiRestricted()) { 169 return; 170 } 171 final int userId = getUserId(); 172 try { 173 if (mPackageInfo.packageName.equals(VpnUtils.getConnectedPackage(mService, userId))) { 174 mService.setAlwaysOnVpnPackage(userId, null, /* lockdownEnabled */ false, 175 /* lockdownWhitelist */ null); 176 mService.prepareVpn(mPackageInfo.packageName, VpnConfig.LEGACY_VPN, userId); 177 } 178 } catch (RemoteException e) { 179 Log.e(TAG, "Failed to disconnect package " + mPackageInfo.packageName + 180 " for user " + userId, e); 181 } 182 } 183 isUiRestricted()184 private boolean isUiRestricted() { 185 final UserHandle userHandle = UserHandle.of(getUserId()); 186 if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_VPN, userHandle)) { 187 return true; 188 } 189 return mPackageInfo.packageName.equals(mDevicePolicyManager.getAlwaysOnVpnPackage()); 190 } 191 getUserId()192 private int getUserId() { 193 return UserHandle.getUserId(mPackageInfo.applicationInfo.uid); 194 } 195 } 196