From 05542603dd4f1e0ea47a3dca01de3999a9a329a9 Mon Sep 17 00:00:00 2001 From: Jeff Davidson Date: Mon, 11 Aug 2014 14:07:27 -0700 Subject: Less intrusive VPN dialog and other UX tweaks. -The ability to launch VPNs is now sticky; once approved by the user, further approvals are not needed UNLESS the connection is revoked in Quick Settings. -The old persistent notification has been removed in favor of the new Quick Settings UI. -The name of the VPN app is now pulled from the label of the VPN service rather than the app itself, if one is set. Bug: 12878887 Bug: 16578022 Change-Id: I102a14c05db26ee3aef030cda971e5165f078a91 --- packages/VpnDialogs/AndroidManifest.xml | 9 - .../VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png | Bin 0 -> 943 bytes .../VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png | Bin 0 -> 629 bytes .../res/drawable-xhdpi/ic_vpn_dialog.png | Bin 0 -> 1035 bytes .../res/drawable-xxhdpi/ic_vpn_dialog.png | Bin 0 -> 1257 bytes .../res/drawable-xxxhdpi/ic_vpn_dialog.png | Bin 0 -> 1884 bytes packages/VpnDialogs/res/layout/confirm.xml | 43 +---- packages/VpnDialogs/res/layout/manage.xml | 45 ----- packages/VpnDialogs/res/values/strings.xml | 41 +---- .../src/com/android/vpndialogs/ConfirmDialog.java | 46 +++-- .../src/com/android/vpndialogs/ManageDialog.java | 204 --------------------- 11 files changed, 42 insertions(+), 346 deletions(-) create mode 100644 packages/VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png create mode 100644 packages/VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png create mode 100644 packages/VpnDialogs/res/drawable-xhdpi/ic_vpn_dialog.png create mode 100644 packages/VpnDialogs/res/drawable-xxhdpi/ic_vpn_dialog.png create mode 100644 packages/VpnDialogs/res/drawable-xxxhdpi/ic_vpn_dialog.png delete mode 100644 packages/VpnDialogs/res/layout/manage.xml delete mode 100644 packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java (limited to 'packages/VpnDialogs') diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml index 03d920a..1768400 100644 --- a/packages/VpnDialogs/AndroidManifest.xml +++ b/packages/VpnDialogs/AndroidManifest.xml @@ -28,14 +28,5 @@ - - - - - - - diff --git a/packages/VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png new file mode 100644 index 0000000..a0b4b61 Binary files /dev/null and b/packages/VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png differ diff --git a/packages/VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png new file mode 100644 index 0000000..df5dfe8 Binary files /dev/null and b/packages/VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png differ diff --git a/packages/VpnDialogs/res/drawable-xhdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-xhdpi/ic_vpn_dialog.png new file mode 100644 index 0000000..18d5a3a Binary files /dev/null and b/packages/VpnDialogs/res/drawable-xhdpi/ic_vpn_dialog.png differ diff --git a/packages/VpnDialogs/res/drawable-xxhdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-xxhdpi/ic_vpn_dialog.png new file mode 100644 index 0000000..4d475dc Binary files /dev/null and b/packages/VpnDialogs/res/drawable-xxhdpi/ic_vpn_dialog.png differ diff --git a/packages/VpnDialogs/res/drawable-xxxhdpi/ic_vpn_dialog.png b/packages/VpnDialogs/res/drawable-xxxhdpi/ic_vpn_dialog.png new file mode 100644 index 0000000..9d458b4 Binary files /dev/null and b/packages/VpnDialogs/res/drawable-xxxhdpi/ic_vpn_dialog.png differ diff --git a/packages/VpnDialogs/res/layout/confirm.xml b/packages/VpnDialogs/res/layout/confirm.xml index ee7f4b8..66fec59 100644 --- a/packages/VpnDialogs/res/layout/confirm.xml +++ b/packages/VpnDialogs/res/layout/confirm.xml @@ -18,41 +18,12 @@ - - - - - - - - - - - - - + android:textSize="18sp" + android:paddingTop="4mm" + android:paddingLeft="3mm" + android:paddingRight="3mm" + android:paddingBottom="4mm"/> diff --git a/packages/VpnDialogs/res/layout/manage.xml b/packages/VpnDialogs/res/layout/manage.xml deleted file mode 100644 index 56332c3..0000000 --- a/packages/VpnDialogs/res/layout/manage.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml index 3ff767a..84206a1 100644 --- a/packages/VpnDialogs/res/values/strings.xml +++ b/packages/VpnDialogs/res/values/strings.xml @@ -17,40 +17,15 @@ - %s - attempts to create a VPN connection. - + Connection request - By proceeding, you are giving the application - permission to intercept all network traffic. - Do NOT accept unless you trust the application. Otherwise, - you run the risk of having your data compromised by a malicious - software. - - - - I trust this application. - - - VPN is connected - - Configure - - Disconnect - - - Session: - - Duration: - - Sent: - - Received: - - - - %1$s bytes / - %2$s packets + %s wants to set up a VPN connection + that allows it to monitor network traffic. Only accept if you trust the source. + +
+ + ]]> appears at the top of your screen when VPN is active.
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java index ddafc66..897c96cf 100644 --- a/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java +++ b/packages/VpnDialogs/src/com/android/vpndialogs/ConfirmDialog.java @@ -18,21 +18,28 @@ package com.android.vpndialogs; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.graphics.drawable.Drawable; import android.net.IConnectivityManager; +import android.net.VpnService; import android.os.ServiceManager; +import android.text.Html; +import android.text.Html.ImageGetter; import android.util.Log; import android.view.View; import android.widget.Button; -import android.widget.CompoundButton; -import android.widget.ImageView; import android.widget.TextView; import com.android.internal.app.AlertActivity; +import com.android.internal.net.VpnConfig; -public class ConfirmDialog extends AlertActivity implements - CompoundButton.OnCheckedChangeListener, DialogInterface.OnClickListener { +import java.util.List; + +public class ConfirmDialog extends AlertActivity + implements DialogInterface.OnClickListener, ImageGetter { private static final String TAG = "VpnConfirm"; private String mPackage; @@ -56,27 +63,22 @@ public class ConfirmDialog extends AlertActivity implements return; } - PackageManager pm = getPackageManager(); - ApplicationInfo app = pm.getApplicationInfo(mPackage, 0); - View view = View.inflate(this, R.layout.confirm, null); - ((ImageView) view.findViewById(R.id.icon)).setImageDrawable(app.loadIcon(pm)); - ((TextView) view.findViewById(R.id.prompt)).setText( - getString(R.string.prompt, app.loadLabel(pm))); - ((CompoundButton) view.findViewById(R.id.check)).setOnCheckedChangeListener(this); - mAlertParams.mIconAttrId = android.R.attr.alertDialogIcon; - mAlertParams.mTitle = getText(android.R.string.dialog_alert_title); + ((TextView) view.findViewById(R.id.warning)).setText( + Html.fromHtml( + getString(R.string.warning, VpnConfig.getVpnLabel(this, mPackage)), + this, null /* tagHandler */)); + + mAlertParams.mTitle = getText(R.string.prompt); mAlertParams.mPositiveButtonText = getText(android.R.string.ok); mAlertParams.mPositiveButtonListener = this; mAlertParams.mNegativeButtonText = getText(android.R.string.cancel); - mAlertParams.mNegativeButtonListener = this; mAlertParams.mView = view; setupAlert(); getWindow().setCloseOnTouchOutside(false); mButton = mAlert.getButton(DialogInterface.BUTTON_POSITIVE); - mButton.setEnabled(false); mButton.setFilterTouchesWhenObscured(true); } catch (Exception e) { Log.e(TAG, "onResume", e); @@ -85,18 +87,24 @@ public class ConfirmDialog extends AlertActivity implements } @Override - public void onBackPressed() { + public Drawable getDrawable(String source) { + // Should only reach this when fetching the VPN icon for the warning string. + Drawable icon = getDrawable(R.drawable.ic_vpn_dialog); + icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight()); + return icon; } @Override - public void onCheckedChanged(CompoundButton button, boolean checked) { - mButton.setEnabled(checked); + public void onBackPressed() { } @Override public void onClick(DialogInterface dialog, int which) { try { - if (which == DialogInterface.BUTTON_POSITIVE && mService.prepareVpn(null, mPackage)) { + if (mService.prepareVpn(null, mPackage)) { + // Authorize this app to initiate VPN connections in the future without user + // intervention. + mService.setVpnPackageAuthorization(true); setResult(RESULT_OK); } } catch (Exception e) { diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java deleted file mode 100644 index eb20995..0000000 --- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2011 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.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.net.IConnectivityManager; -import android.os.Handler; -import android.os.Message; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.util.Log; -import android.view.View; -import android.widget.TextView; - -import com.android.internal.app.AlertActivity; -import com.android.internal.net.VpnConfig; - -import java.io.DataInputStream; -import java.io.FileInputStream; - -public class ManageDialog extends AlertActivity implements - DialogInterface.OnClickListener, Handler.Callback { - private static final String TAG = "VpnManage"; - - private VpnConfig mConfig; - - private IConnectivityManager mService; - - private TextView mDuration; - private TextView mDataTransmitted; - private TextView mDataReceived; - private boolean mDataRowsHidden; - - private Handler mHandler; - - @Override - protected void onResume() { - super.onResume(); - - if (getCallingPackage() != null) { - Log.e(TAG, getCallingPackage() + " cannot start this activity"); - finish(); - return; - } - - try { - - mService = IConnectivityManager.Stub.asInterface( - ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); - - mConfig = mService.getVpnConfig(); - - // mConfig can be null if we are a restricted user, in that case don't show this dialog - if (mConfig == null) { - finish(); - return; - } - - View view = View.inflate(this, R.layout.manage, null); - if (mConfig.session != null) { - ((TextView) view.findViewById(R.id.session)).setText(mConfig.session); - } - mDuration = (TextView) view.findViewById(R.id.duration); - mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted); - mDataReceived = (TextView) view.findViewById(R.id.data_received); - mDataRowsHidden = true; - - if (mConfig.legacy) { - mAlertParams.mIconId = android.R.drawable.ic_dialog_info; - mAlertParams.mTitle = getText(R.string.legacy_title); - } else { - PackageManager pm = getPackageManager(); - ApplicationInfo app = pm.getApplicationInfo(mConfig.user, 0); - mAlertParams.mIcon = app.loadIcon(pm); - mAlertParams.mTitle = app.loadLabel(pm); - } - if (mConfig.configureIntent != null) { - mAlertParams.mPositiveButtonText = getText(R.string.configure); - mAlertParams.mPositiveButtonListener = this; - } - mAlertParams.mNeutralButtonText = getText(R.string.disconnect); - mAlertParams.mNeutralButtonListener = this; - mAlertParams.mNegativeButtonText = getText(android.R.string.cancel); - mAlertParams.mNegativeButtonListener = this; - mAlertParams.mView = view; - setupAlert(); - - if (mHandler == null) { - mHandler = new Handler(this); - } - mHandler.sendEmptyMessage(0); - } catch (Exception e) { - Log.e(TAG, "onResume", e); - finish(); - } - } - - @Override - protected void onPause() { - super.onPause(); - if (!isFinishing()) { - finish(); - } - } - - @Override - public void onClick(DialogInterface dialog, int which) { - try { - if (which == DialogInterface.BUTTON_POSITIVE) { - mConfig.configureIntent.send(); - } else if (which == DialogInterface.BUTTON_NEUTRAL) { - if (mConfig.legacy) { - mService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN); - } else { - mService.prepareVpn(mConfig.user, VpnConfig.LEGACY_VPN); - } - } - } catch (Exception e) { - Log.e(TAG, "onClick", e); - finish(); - } - } - - @Override - public boolean handleMessage(Message message) { - mHandler.removeMessages(0); - - if (!isFinishing()) { - if (mConfig.startTime != -1) { - long seconds = (SystemClock.elapsedRealtime() - mConfig.startTime) / 1000; - mDuration.setText(String.format("%02d:%02d:%02d", - seconds / 3600, seconds / 60 % 60, seconds % 60)); - } - - String[] numbers = getNumbers(); - if (numbers != null) { - // First unhide the related data rows. - if (mDataRowsHidden) { - findViewById(R.id.data_transmitted_row).setVisibility(View.VISIBLE); - findViewById(R.id.data_received_row).setVisibility(View.VISIBLE); - mDataRowsHidden = false; - } - - // [1] and [2] are received data in bytes and packets. - mDataReceived.setText(getString(R.string.data_value_format, - numbers[1], numbers[2])); - - // [9] and [10] are transmitted data in bytes and packets. - mDataTransmitted.setText(getString(R.string.data_value_format, - numbers[9], numbers[10])); - } - mHandler.sendEmptyMessageDelayed(0, 1000); - } - return true; - } - - private String[] getNumbers() { - DataInputStream in = null; - try { - // See dev_seq_printf_stats() in net/core/dev.c. - in = new DataInputStream(new FileInputStream("/proc/net/dev")); - String prefix = mConfig.interfaze + ':'; - - while (true) { - String line = in.readLine().trim(); - if (line.startsWith(prefix)) { - String[] numbers = line.substring(prefix.length()).split(" +"); - for (int i = 1; i < 17; ++i) { - if (!numbers[i].equals("0")) { - return numbers; - } - } - break; - } - } - } catch (Exception e) { - // ignore - } finally { - try { - in.close(); - } catch (Exception e) { - // ignore - } - } - return null; - } -} -- cgit v1.1