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