diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index bc02ea021632e..337c4b5184533 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2191,10 +2191,14 @@ com.android.systemui/com.android.systemui.usb.UsbDebuggingSecondaryUserActivity - - + com.android.vpndialogs/com.android.vpndialogs.ConfirmDialog + + com.android.vpndialogs/com.android.vpndialogs.AlwaysOnDisconnectedDialog + ;com.android.settings; diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index c977020692109..974e2179061b6 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3440,16 +3440,21 @@ Connected to %s. Tap to manage the network. - + Always-on VPN connecting\u2026 - + Always-on VPN connected - - Always-on VPN disconnected - + + Disconnected from always-on VPN + Always-on VPN error - - Tap to set up + + Change network or VPN settings diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 71cb8fef275e2..8ad425ae7eca8 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1999,6 +1999,7 @@ + diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml index a3d27ce8a3dab..8172e717850bd 100644 --- a/packages/VpnDialogs/AndroidManifest.xml +++ b/packages/VpnDialogs/AndroidManifest.xml @@ -23,9 +23,10 @@ + android:allowBackup="false"> + + android:theme="@android:style/Theme.Material.Light.Dialog.Alert"> @@ -33,12 +34,21 @@ - - - - + android:theme="@android:style/Theme.Material.Light.Dialog.Alert" + android:noHistory="true" + android:excludeFromRecents="true" + android:permission="android.permission.NETWORK_SETTINGS" + android:exported="true"> + + + + diff --git a/packages/VpnDialogs/res/layout/always_on_disconnected.xml b/packages/VpnDialogs/res/layout/always_on_disconnected.xml new file mode 100644 index 0000000000000..0f4a46d07a9a6 --- /dev/null +++ b/packages/VpnDialogs/res/layout/always_on_disconnected.xml @@ -0,0 +1,25 @@ + + + + + + diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml index 406bcc34a1015..443a9bc33b90f 100644 --- a/packages/VpnDialogs/res/values/strings.xml +++ b/packages/VpnDialogs/res/values/strings.xml @@ -18,7 +18,6 @@ Connection request - %s wants to set up a VPN connection that allows it to monitor network traffic. Only accept if you trust the source. @@ -31,11 +30,6 @@ VPN is connected - - Configure - - Disconnect - Session: @@ -44,10 +38,55 @@ Sent: Received: - %1$s bytes / %2$s packets + + + Can\'t connect to always-on VPN + + + %1$s is set up to stay connected all + the time, but it can\'t connect right now. Your phone will use a public network until it can + reconnect to %1$s. + + + + %1$s is set up to stay connected all + the time, but it can\'t connect right now. You won\'t have a connection until the VPN can + reconnect. + + + " " + + Change VPN settings + + + Configure + + Disconnect + + Open app + + Dismiss + diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java new file mode 100644 index 0000000000000..846fcf867e328 --- /dev/null +++ b/packages/VpnDialogs/src/com/android/vpndialogs/AlwaysOnDisconnectedDialog.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.vpndialogs; + +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.IConnectivityManager; +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.os.UserHandle; +import android.provider.Settings; +import android.text.SpannableStringBuilder; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; +import android.util.Log; +import android.view.View; +import android.view.WindowManager; +import android.widget.TextView; + +import com.android.internal.app.AlertActivity; +import com.android.internal.net.VpnConfig; + +public class AlwaysOnDisconnectedDialog extends AlertActivity + implements DialogInterface.OnClickListener{ + + private static final String TAG = "VpnDisconnected"; + + private IConnectivityManager mService; + private int mUserId; + private String mVpnPackage; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mService = IConnectivityManager.Stub.asInterface( + ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); + mUserId = UserHandle.myUserId(); + mVpnPackage = getAlwaysOnVpnPackage(); + if (mVpnPackage == null) { + finish(); + return; + } + + View view = View.inflate(this, R.layout.always_on_disconnected, null); + TextView messageView = view.findViewById(R.id.message); + messageView.setText(getMessage(getIntent().getBooleanExtra("lockdown", false))); + messageView.setMovementMethod(LinkMovementMethod.getInstance()); + + mAlertParams.mTitle = getString(R.string.always_on_disconnected_title); + mAlertParams.mPositiveButtonText = getString(R.string.open_app); + mAlertParams.mPositiveButtonListener = this; + mAlertParams.mNegativeButtonText = getString(R.string.dismiss); + mAlertParams.mNegativeButtonListener = this; + mAlertParams.mCancelable = false; + mAlertParams.mView = view; + setupAlert(); + + getWindow().setCloseOnTouchOutside(false); + getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + } + + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case BUTTON_POSITIVE: + PackageManager pm = getPackageManager(); + final Intent intent = pm.getLaunchIntentForPackage(mVpnPackage); + if (intent != null) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(intent); + } + finish(); + break; + case BUTTON_NEGATIVE: + finish(); + break; + default: + break; + } + } + + private String getAlwaysOnVpnPackage() { + try { + return mService.getAlwaysOnVpnPackage(mUserId); + } catch (RemoteException e) { + Log.e(TAG, "Can't getAlwaysOnVpnPackage()", e); + return null; + } + } + + private CharSequence getVpnLabel() { + try { + return VpnConfig.getVpnLabel(this, mVpnPackage); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Can't getVpnLabel() for " + mVpnPackage, e); + return mVpnPackage; + } + } + + private CharSequence getMessage(boolean isLockdown) { + final SpannableStringBuilder message = new SpannableStringBuilder(); + final int baseMessageResId = isLockdown + ? R.string.always_on_disconnected_message_lockdown + : R.string.always_on_disconnected_message; + message.append(getString(baseMessageResId, getVpnLabel())); + message.append(getString(R.string.always_on_disconnected_message_separator)); + message.append(getString(R.string.always_on_disconnected_message_settings_link), + new VpnSpan(), 0 /*flags*/); + return message; + } + + private class VpnSpan extends ClickableSpan { + @Override + public void onClick(View unused) { + final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + startActivity(intent); + } + } +} diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java index 2fe6648d82dac..01dca7e30e64b 100644 --- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java +++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java @@ -54,12 +54,6 @@ public class ManageDialog extends AlertActivity implements protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - if (getCallingPackage() != null) { - Log.e(TAG, getCallingPackage() + " cannot start this activity"); - finish(); - return; - } - try { mService = IConnectivityManager.Stub.asInterface( diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index e82eabfe5ad9b..225d7083748f0 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -1416,7 +1416,11 @@ public class Vpn { notificationManager.cancelAsUser(TAG, SystemMessage.NOTE_VPN_DISCONNECTED, user); return; } - final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS); + final Intent intent = new Intent(); + intent.setComponent(ComponentName.unflattenFromString(mContext.getString( + R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))); + intent.putExtra("lockdown", mLockdown); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); final PendingIntent configIntent = mSystemServices.pendingIntentGetActivityAsUser( intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT, user); final Notification.Builder builder =