am baf519c9: am 9f207f97: am 78595786: Merge "Restore legacy VPN stats dialog." into lmp-dev

* commit 'baf519c9599a7ecb06db3281746708e5ccdeb10c':
  Restore legacy VPN stats dialog.
This commit is contained in:
Jeff Davidson
2014-08-25 08:23:13 +00:00
committed by Android Git Automerger
6 changed files with 293 additions and 8 deletions

View File

@@ -40,6 +40,7 @@ public class LegacyVpnInfo implements Parcelable {
public String key;
public int state = -1;
public PendingIntent intent;
@Override
public int describeContents() {
@@ -50,6 +51,7 @@ public class LegacyVpnInfo implements Parcelable {
public void writeToParcel(Parcel out, int flags) {
out.writeString(key);
out.writeInt(state);
out.writeParcelable(intent, flags);
}
public static final Parcelable.Creator<LegacyVpnInfo> CREATOR =
@@ -59,6 +61,7 @@ public class LegacyVpnInfo implements Parcelable {
LegacyVpnInfo info = new LegacyVpnInfo();
info.key = in.readString();
info.state = in.readInt();
info.intent = in.readParcelable(null);
return info;
}

View File

@@ -28,6 +28,7 @@ import android.net.LinkAddress;
import android.net.RouteInfo;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import java.net.Inet4Address;
import java.net.InetAddress;
@@ -57,6 +58,15 @@ public class VpnConfig implements Parcelable {
return intent;
}
/** NOTE: This should only be used for legacy VPN. */
public static PendingIntent getIntentForStatusPanel(Context context) {
Intent intent = new Intent();
intent.setClassName(DIALOGS_PACKAGE, DIALOGS_PACKAGE + ".ManageDialog");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NO_HISTORY |
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
return PendingIntent.getActivityAsUser(context, 0, intent, 0, null, UserHandle.CURRENT);
}
public static CharSequence getVpnLabel(Context context, String packageName)
throws NameNotFoundException {
PackageManager pm = context.getPackageManager();

View File

@@ -28,5 +28,14 @@
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity android:name=".ManageDialog"
android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert"
android:noHistory="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="3mm"
android:stretchColumns="0,1"
android:shrinkColumns="1">
<TableRow>
<TextView android:text="@string/session" style="@style/label"/>
<TextView android:id="@+id/session" style="@style/value"/>
</TableRow>
<TableRow>
<TextView android:text="@string/duration" style="@style/label"/>
<TextView android:id="@+id/duration" style="@style/value"/>
</TableRow>
<TableRow android:id="@+id/data_transmitted_row" android:visibility="gone">
<TextView android:text="@string/data_transmitted" style="@style/label"/>
<TextView android:id="@+id/data_transmitted" style="@style/value"/>
</TableRow>
<TableRow android:id="@+id/data_received_row" android:visibility="gone">
<TextView android:text="@string/data_received" style="@style/label"/>
<TextView android:id="@+id/data_received" style="@style/value"/>
</TableRow>
</TableLayout>

View File

@@ -0,0 +1,198 @@
/*
* 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.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.mTitle = getText(R.string.legacy_title);
} else {
mAlertParams.mTitle = VpnConfig.getVpnLabel(this, mConfig.user);
}
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;
}
}

View File

@@ -22,6 +22,7 @@ import static android.system.OsConstants.AF_INET6;
import android.app.AppGlobals;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -105,6 +106,7 @@ public class Vpn {
private boolean mAllowIPv6;
private Connection mConnection;
private LegacyVpnRunner mLegacyVpnRunner;
private PendingIntent mStatusIntent;
private volatile boolean mEnableTeardown = true;
private final IConnectivityManager mConnService;
private final INetworkManagementService mNetd;
@@ -237,6 +239,7 @@ public class Vpn {
// Reset the interface.
if (mInterface != null) {
mStatusIntent = null;
agentDisconnect();
jniReset(mInterface);
mInterface = null;
@@ -567,17 +570,20 @@ public class Vpn {
// add the user
mVpnUsers.add(UidRange.createForUser(user));
prepareStatusIntent();
}
private void removeVpnUserLocked(int user) {
if (!isRunningLocked()) {
throw new IllegalStateException("VPN is not active");
}
UidRange uidRange = UidRange.createForUser(user);
if (mNetworkAgent != null) {
mNetworkAgent.removeUidRanges(new UidRange[] { uidRange });
}
mVpnUsers.remove(uidRange);
if (!isRunningLocked()) {
throw new IllegalStateException("VPN is not active");
}
UidRange uidRange = UidRange.createForUser(user);
if (mNetworkAgent != null) {
mNetworkAgent.removeUidRanges(new UidRange[] { uidRange });
}
mVpnUsers.remove(uidRange);
mStatusIntent = null;
}
private void onUserAdded(int userId) {
@@ -645,6 +651,7 @@ public class Vpn {
public void interfaceRemoved(String interfaze) {
synchronized (Vpn.this) {
if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
mStatusIntent = null;
mVpnUsers = null;
mInterface = null;
if (mConnection != null) {
@@ -702,6 +709,15 @@ public class Vpn {
}
}
private void prepareStatusIntent() {
final long token = Binder.clearCallingIdentity();
try {
mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext);
} finally {
Binder.restoreCallingIdentity(token);
}
}
public synchronized boolean addAddress(String address, int prefixLength) {
if (Binder.getCallingUid() != mOwnerUID || mInterface == null || mNetworkAgent == null) {
return false;
@@ -911,6 +927,9 @@ public class Vpn {
final LegacyVpnInfo info = new LegacyVpnInfo();
info.key = mConfig.user;
info.state = LegacyVpnInfo.stateFromNetworkInfo(mNetworkInfo);
if (mNetworkInfo.isConnected()) {
info.intent = mStatusIntent;
}
return info;
}