Merge "Less intrusive VPN dialog and other UX tweaks." into lmp-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
c8f0ffa297
@@ -16,25 +16,25 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SystemApi;
|
||||
import android.app.usage.UsageStatsManager;
|
||||
import android.content.Context;
|
||||
import android.media.AudioAttributes.AttributeUsage;
|
||||
import android.os.Binder;
|
||||
import android.os.IBinder;
|
||||
import android.os.UserManager;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.android.internal.app.IAppOpsService;
|
||||
import com.android.internal.app.IAppOpsCallback;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
import android.os.UserManager;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import com.android.internal.app.IAppOpsCallback;
|
||||
import com.android.internal.app.IAppOpsService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* API for interacting with "application operation" tracking.
|
||||
@@ -203,8 +203,10 @@ public class AppOpsManager {
|
||||
public static final int OP_TOAST_WINDOW = 45;
|
||||
/** @hide Capture the device's display contents and/or audio */
|
||||
public static final int OP_PROJECT_MEDIA = 46;
|
||||
/** @hide Activate a VPN connection without user intervention. */
|
||||
public static final int OP_ACTIVATE_VPN = 47;
|
||||
/** @hide */
|
||||
public static final int _NUM_OP = 47;
|
||||
public static final int _NUM_OP = 48;
|
||||
|
||||
/** Access to coarse location information. */
|
||||
public static final String OPSTR_COARSE_LOCATION =
|
||||
@@ -218,6 +220,9 @@ public class AppOpsManager {
|
||||
/** Continually monitoring location data with a relatively high power request. */
|
||||
public static final String OPSTR_MONITOR_HIGH_POWER_LOCATION
|
||||
= "android:monitor_location_high_power";
|
||||
/** Activate a VPN connection without user intervention. @hide */
|
||||
@SystemApi
|
||||
public static final String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
|
||||
|
||||
/**
|
||||
* This maps each operation to the operation that serves as the
|
||||
@@ -275,6 +280,7 @@ public class AppOpsManager {
|
||||
OP_MUTE_MICROPHONE,
|
||||
OP_TOAST_WINDOW,
|
||||
OP_PROJECT_MEDIA,
|
||||
OP_ACTIVATE_VPN,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -329,6 +335,7 @@ public class AppOpsManager {
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
OPSTR_ACTIVATE_VPN,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -383,6 +390,7 @@ public class AppOpsManager {
|
||||
"MUTE_MICROPHONE",
|
||||
"TOAST_WINDOW",
|
||||
"PROJECT_MEDIA",
|
||||
"ACTIVATE_VPN",
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -437,6 +445,7 @@ public class AppOpsManager {
|
||||
null, // no permission for muting/unmuting microphone
|
||||
null, // no permission for displaying toasts
|
||||
null, // no permission for projecting media
|
||||
null, // no permission for activating vpn
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -492,6 +501,7 @@ public class AppOpsManager {
|
||||
UserManager.DISALLOW_UNMUTE_MICROPHONE, // MUTE_MICROPHONE
|
||||
UserManager.DISALLOW_CREATE_WINDOWS, // TOAST_WINDOW
|
||||
null, //PROJECT_MEDIA
|
||||
UserManager.DISALLOW_CONFIG_VPN, // ACTIVATE_VPN
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -546,6 +556,7 @@ public class AppOpsManager {
|
||||
false, //MUTE_MICROPHONE
|
||||
true, //TOAST_WINDOW
|
||||
false, //PROJECT_MEDIA
|
||||
false, //ACTIVATE_VPN
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -599,6 +610,7 @@ public class AppOpsManager {
|
||||
AppOpsManager.MODE_ALLOWED,
|
||||
AppOpsManager.MODE_ALLOWED,
|
||||
AppOpsManager.MODE_IGNORED, // OP_PROJECT_MEDIA
|
||||
AppOpsManager.MODE_IGNORED, // OP_ACTIVATE_VPN
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -656,6 +668,7 @@ public class AppOpsManager {
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
};
|
||||
|
||||
private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
|
||||
|
||||
@@ -108,6 +108,8 @@ interface IConnectivityManager
|
||||
|
||||
boolean prepareVpn(String oldPackage, String newPackage);
|
||||
|
||||
void setVpnPackageAuthorization(boolean authorized);
|
||||
|
||||
ParcelFileDescriptor establishVpn(in VpnConfig config);
|
||||
|
||||
VpnConfig getVpnConfig();
|
||||
|
||||
@@ -40,7 +40,6 @@ public class LegacyVpnInfo implements Parcelable {
|
||||
|
||||
public String key;
|
||||
public int state = -1;
|
||||
public PendingIntent intent;
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
@@ -51,7 +50,6 @@ 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 =
|
||||
@@ -61,7 +59,6 @@ public class LegacyVpnInfo implements Parcelable {
|
||||
LegacyVpnInfo info = new LegacyVpnInfo();
|
||||
info.key = in.readString();
|
||||
info.state = in.readInt();
|
||||
info.intent = in.readParcelable(null);
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,17 +20,19 @@ import android.app.PendingIntent;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.RouteInfo;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.LinkAddress;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A simple container used to carry information in VpnBuilder, VpnDialogs,
|
||||
@@ -55,12 +57,19 @@ public class VpnConfig implements Parcelable {
|
||||
return intent;
|
||||
}
|
||||
|
||||
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();
|
||||
Intent intent = new Intent(SERVICE_INTERFACE);
|
||||
intent.setPackage(packageName);
|
||||
List<ResolveInfo> services = pm.queryIntentServices(intent, 0 /* flags */);
|
||||
if (services != null && services.size() == 1) {
|
||||
// This app contains exactly one VPN service. Call loadLabel, which will attempt to
|
||||
// load the service's label, and fall back to the app label if none is present.
|
||||
return services.get(0).loadLabel(pm);
|
||||
} else {
|
||||
return pm.getApplicationInfo(packageName, 0).loadLabel(pm);
|
||||
}
|
||||
}
|
||||
|
||||
public String user;
|
||||
|
||||
@@ -834,8 +834,8 @@
|
||||
<!-- Monitoring dialog title for normal devices [CHAR LIMIT=35]-->
|
||||
<string name="monitoring_title">Network monitoring</string>
|
||||
|
||||
<!-- Monitoring dialog open app button [CHAR LIMIT=30] -->
|
||||
<string name="open_app">Open app</string>
|
||||
<!-- Monitoring dialog disable vpn button [CHAR LIMIT=30] -->
|
||||
<string name="disable_vpn">Disable VPN</string>
|
||||
|
||||
<!-- Monitoring dialog disconnect vpn button [CHAR LIMIT=30] -->
|
||||
<string name="disconnect_vpn">Disconnect VPN</string>
|
||||
|
||||
@@ -119,11 +119,7 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which == DialogInterface.BUTTON_NEGATIVE) {
|
||||
if (mSecurityController.isLegacyVpn()) {
|
||||
mSecurityController.disconnectFromLegacyVpn();
|
||||
} else {
|
||||
mSecurityController.openVpnApp();
|
||||
}
|
||||
mSecurityController.disconnectFromVpn();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,7 +138,7 @@ public class QSFooter implements OnClickListener, DialogInterface.OnClickListene
|
||||
if (mSecurityController.isLegacyVpn()) {
|
||||
return mContext.getString(R.string.disconnect_vpn);
|
||||
} else {
|
||||
return mContext.getString(R.string.open_app);
|
||||
return mContext.getString(R.string.disable_vpn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,7 @@ public interface SecurityController {
|
||||
String getVpnApp();
|
||||
boolean isLegacyVpn();
|
||||
String getLegacyVpnName();
|
||||
void openVpnApp();
|
||||
void disconnectFromLegacyVpn();
|
||||
void disconnectFromVpn();
|
||||
|
||||
void addCallback(VpnCallback callback);
|
||||
void removeCallback(VpnCallback callback);
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.systemui.statusbar.policy;
|
||||
import android.app.admin.DevicePolicyManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.ConnectivityManager.NetworkCallback;
|
||||
@@ -109,18 +108,17 @@ public class SecurityControllerImpl implements SecurityController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openVpnApp() {
|
||||
Intent i = mContext.getPackageManager().getLaunchIntentForPackage(mVpnConfig.user);
|
||||
if (i != null) {
|
||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
mContext.startActivity(i);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnectFromLegacyVpn() {
|
||||
public void disconnectFromVpn() {
|
||||
try {
|
||||
mConnectivityService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
|
||||
if (isLegacyVpn()) {
|
||||
mConnectivityService.prepareVpn(VpnConfig.LEGACY_VPN, VpnConfig.LEGACY_VPN);
|
||||
} else {
|
||||
// Prevent this app from initiating VPN connections in the future without user
|
||||
// intervention.
|
||||
mConnectivityService.setVpnPackageAuthorization(false);
|
||||
|
||||
mConnectivityService.prepareVpn(mVpnConfig.user, VpnConfig.LEGACY_VPN);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Unable to disconnect from VPN", e);
|
||||
}
|
||||
@@ -154,9 +152,7 @@ public class SecurityControllerImpl implements SecurityController {
|
||||
mIsVpnEnabled = mVpnConfig != null;
|
||||
|
||||
if (mVpnConfig != null && !mVpnConfig.legacy) {
|
||||
ApplicationInfo info =
|
||||
mContext.getPackageManager().getApplicationInfo(mVpnConfig.user, 0);
|
||||
mVpnName = mContext.getPackageManager().getApplicationLabel(info).toString();
|
||||
mVpnName = VpnConfig.getVpnLabel(mContext, mVpnConfig.user).toString();
|
||||
}
|
||||
} catch (RemoteException | NameNotFoundException e) {
|
||||
Log.w(TAG, "Unable to get current VPN", e);
|
||||
|
||||
@@ -28,14 +28,5 @@
|
||||
<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>
|
||||
|
||||
BIN
packages/VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png
Normal file
BIN
packages/VpnDialogs/res/drawable-hdpi/ic_vpn_dialog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 943 B |
BIN
packages/VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png
Normal file
BIN
packages/VpnDialogs/res/drawable-mdpi/ic_vpn_dialog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 629 B |
BIN
packages/VpnDialogs/res/drawable-xhdpi/ic_vpn_dialog.png
Normal file
BIN
packages/VpnDialogs/res/drawable-xhdpi/ic_vpn_dialog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
packages/VpnDialogs/res/drawable-xxhdpi/ic_vpn_dialog.png
Normal file
BIN
packages/VpnDialogs/res/drawable-xxhdpi/ic_vpn_dialog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
packages/VpnDialogs/res/drawable-xxxhdpi/ic_vpn_dialog.png
Normal file
BIN
packages/VpnDialogs/res/drawable-xxxhdpi/ic_vpn_dialog.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
@@ -18,41 +18,12 @@
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
<TextView android:id="@+id/warning"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="3mm">
|
||||
|
||||
<LinearLayout android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView android:id="@+id/icon"
|
||||
android:layout_width="@android:dimen/app_icon_size"
|
||||
android:layout_height="@android:dimen/app_icon_size"
|
||||
android:paddingRight="1mm"/>
|
||||
|
||||
<TextView android:id="@+id/prompt"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="18sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView android:id="@+id/warning"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="1mm"
|
||||
android:paddingBottom="1mm"
|
||||
android:text="@string/warning"
|
||||
android:textSize="18sp"/>
|
||||
|
||||
<CheckBox android:id="@+id/check"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/accept"
|
||||
android:textSize="20sp"
|
||||
android:filterTouchesWhenObscured="true"
|
||||
android:checked="false"/>
|
||||
</LinearLayout>
|
||||
android:textSize="18sp"
|
||||
android:paddingTop="4mm"
|
||||
android:paddingLeft="3mm"
|
||||
android:paddingRight="3mm"
|
||||
android:paddingBottom="4mm"/>
|
||||
</ScrollView>
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
<?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>
|
||||
@@ -17,40 +17,15 @@
|
||||
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
|
||||
|
||||
<!-- Dialog title to identify the request from a VPN application. [CHAR LIMIT=60] -->
|
||||
<string name="prompt"><xliff:g id="app">%s</xliff:g>
|
||||
attempts to create a VPN connection.
|
||||
</string>
|
||||
<string name="prompt">Connection request</string>
|
||||
|
||||
<!-- Dialog message to warn about the risk of using a VPN application. [CHAR LIMIT=NONE] -->
|
||||
<string name="warning">By proceeding, you are giving the application
|
||||
permission to intercept all network traffic.
|
||||
<b>Do NOT accept unless you trust the application.</b> Otherwise,
|
||||
you run the risk of having your data compromised by a malicious
|
||||
software.
|
||||
</string>
|
||||
|
||||
<!-- Checkbox label to accept the request from a VPN application. [CHAR LIMIT=60] -->
|
||||
<string name="accept">I trust this application.</string>
|
||||
|
||||
<!-- Dialog title for built-in VPN. [CHAR LIMIT=40] -->
|
||||
<string name="legacy_title">VPN is connected</string>
|
||||
<!-- Button label to configure the current VPN session. [CHAR LIMIT=20] -->
|
||||
<string name="configure">Configure</string>
|
||||
<!-- Button label to disconnect the current VPN session. [CHAR LIMIT=20] -->
|
||||
<string name="disconnect">Disconnect</string>
|
||||
|
||||
<!-- Label for the name of the current VPN session. [CHAR LIMIT=20] -->
|
||||
<string name="session">Session:</string>
|
||||
<!-- Label for the duration of the current VPN session. [CHAR LIMIT=20] -->
|
||||
<string name="duration">Duration:</string>
|
||||
<!-- Label for the network usage of data transmitted over VPN. [CHAR LIMIT=20] -->
|
||||
<string name="data_transmitted">Sent:</string>
|
||||
<!-- Label for the network usage of data received over VPN. [CHAR LIMIT=20] -->
|
||||
<string name="data_received">Received:</string>
|
||||
|
||||
<!-- Formatted string for the network usage over VPN. [CHAR LIMIT=40] -->
|
||||
<string name="data_value_format">
|
||||
<xliff:g id="number">%1$s</xliff:g> bytes /
|
||||
<xliff:g id="number">%2$s</xliff:g> packets
|
||||
<string name="warning"><xliff:g id="app">%s</xliff:g> wants to set up a VPN connection
|
||||
that allows it to monitor network traffic. Only accept if you trust the source.
|
||||
<![CDATA[
|
||||
<br />
|
||||
<br />
|
||||
<img src="vpn_icon" />
|
||||
]]> appears at the top of your screen when VPN is active.
|
||||
</string>
|
||||
</resources>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -2662,6 +2662,20 @@ public class ConnectivityService extends IConnectivityManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the current VPN package has the ability to launch VPNs without
|
||||
* user intervention. This method is used by system UIs and not available
|
||||
* in ConnectivityManager. Permissions are checked in Vpn class.
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void setVpnPackageAuthorization(boolean authorized) {
|
||||
int user = UserHandle.getUserId(Binder.getCallingUid());
|
||||
synchronized(mVpns) {
|
||||
mVpns.get(user).setPackageAuthorization(authorized);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a TUN interface and return its file descriptor. Parameters
|
||||
* are encoded and opaque to this class. This method is used by VpnBuilder
|
||||
|
||||
@@ -21,9 +21,7 @@ import static android.system.OsConstants.AF_INET;
|
||||
import static android.system.OsConstants.AF_INET6;
|
||||
|
||||
import android.app.AppGlobals;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.AppOpsManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
@@ -35,10 +33,6 @@ import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.content.pm.UserInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.BaseNetworkStateTracker;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.IConnectivityManager;
|
||||
import android.net.INetworkManagementEventObserver;
|
||||
@@ -51,7 +45,6 @@ import android.net.NetworkCapabilities;
|
||||
import android.net.NetworkInfo;
|
||||
import android.net.NetworkInfo.DetailedState;
|
||||
import android.net.NetworkMisc;
|
||||
import android.net.NetworkUtils;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.UidRange;
|
||||
import android.os.Binder;
|
||||
@@ -70,15 +63,15 @@ import android.os.UserManager;
|
||||
import android.security.Credentials;
|
||||
import android.security.KeyStore;
|
||||
import android.util.Log;
|
||||
import android.util.SparseBooleanArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.net.LegacyVpnInfo;
|
||||
import com.android.internal.net.VpnConfig;
|
||||
import com.android.internal.net.VpnProfile;
|
||||
import com.android.server.net.BaseNetworkObserver;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -92,8 +85,6 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import libcore.io.IoUtils;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -114,8 +105,6 @@ public class Vpn {
|
||||
private boolean mAllowIPv6;
|
||||
private Connection mConnection;
|
||||
private LegacyVpnRunner mLegacyVpnRunner;
|
||||
private PendingIntent mStatusIntent;
|
||||
private volatile boolean mEnableNotif = true;
|
||||
private volatile boolean mEnableTeardown = true;
|
||||
private final IConnectivityManager mConnService;
|
||||
private final INetworkManagementService mNetd;
|
||||
@@ -179,14 +168,6 @@ public class Vpn {
|
||||
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if this object is responsible for showing its own notifications. When
|
||||
* {@code false}, notifications are handled externally by someone else.
|
||||
*/
|
||||
public void setEnableNotifications(boolean enableNotif) {
|
||||
mEnableNotif = enableNotif;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if this object is responsible for watching for {@link NetworkInfo}
|
||||
* teardown. When {@code false}, teardown is handled externally by someone
|
||||
@@ -228,6 +209,20 @@ public class Vpn {
|
||||
public synchronized boolean prepare(String oldPackage, String newPackage) {
|
||||
// Return false if the package does not match.
|
||||
if (oldPackage != null && !oldPackage.equals(mPackage)) {
|
||||
// The package doesn't match. If this VPN was not previously authorized, return false
|
||||
// to force user authorization. Otherwise, revoke the VPN anyway.
|
||||
if (!oldPackage.equals(VpnConfig.LEGACY_VPN) && isVpnUserPreConsented(oldPackage)) {
|
||||
long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
// This looks bizarre, but it is what ConfirmDialog in VpnDialogs is doing when
|
||||
// the user clicks through to allow the VPN to consent. So we are emulating the
|
||||
// action of the dialog without actually showing it.
|
||||
prepare(null, oldPackage);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -240,11 +235,8 @@ public class Vpn {
|
||||
// Check if the caller is authorized.
|
||||
enforceControlPermission();
|
||||
|
||||
// Reset the interface and hide the notification.
|
||||
// Reset the interface.
|
||||
if (mInterface != null) {
|
||||
for (UidRange uidRange : mVpnUsers) {
|
||||
hideNotification(uidRange.getStartUser());
|
||||
}
|
||||
agentDisconnect();
|
||||
jniReset(mInterface);
|
||||
mInterface = null;
|
||||
@@ -287,12 +279,46 @@ public class Vpn {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
mConfig = null;
|
||||
|
||||
updateState(DetailedState.IDLE, "prepare");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether the current package has the ability to launch VPNs without user intervention.
|
||||
*/
|
||||
public void setPackageAuthorization(boolean authorized) {
|
||||
// Check if the caller is authorized.
|
||||
enforceControlPermission();
|
||||
|
||||
if (mPackage == null || VpnConfig.LEGACY_VPN.equals(mPackage)) {
|
||||
return;
|
||||
}
|
||||
|
||||
long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
AppOpsManager appOps =
|
||||
(AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
|
||||
appOps.setMode(AppOpsManager.OP_ACTIVATE_VPN, mOwnerUID, mPackage,
|
||||
authorized ? AppOpsManager.MODE_ALLOWED : AppOpsManager.MODE_IGNORED);
|
||||
} catch (Exception e) {
|
||||
Log.wtf(TAG, "Failed to set app ops for package " + mPackage, e);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isVpnUserPreConsented(String packageName) {
|
||||
AppOpsManager appOps =
|
||||
(AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
|
||||
|
||||
// Verify that the caller matches the given package and has permission to activate VPNs.
|
||||
return appOps.noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Binder.getCallingUid(),
|
||||
packageName) == AppOpsManager.MODE_ALLOWED;
|
||||
}
|
||||
|
||||
private int getAppUid(String app) {
|
||||
if (app == VpnConfig.LEGACY_VPN) {
|
||||
if (VpnConfig.LEGACY_VPN.equals(app)) {
|
||||
return Process.myUid();
|
||||
}
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
@@ -355,9 +381,10 @@ public class Vpn {
|
||||
try {
|
||||
mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE,
|
||||
mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) {
|
||||
@Override
|
||||
public void unwanted() {
|
||||
// We are user controlled, not driven by NetworkRequest.
|
||||
};
|
||||
}
|
||||
};
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
@@ -540,39 +567,6 @@ public class Vpn {
|
||||
|
||||
// add the user
|
||||
mVpnUsers.add(UidRange.createForUser(user));
|
||||
|
||||
// show the notification
|
||||
if (!mPackage.equals(VpnConfig.LEGACY_VPN)) {
|
||||
// Load everything for the user's notification
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
ApplicationInfo app = null;
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
app = AppGlobals.getPackageManager().getApplicationInfo(mPackage, 0, mUserId);
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException("Invalid application");
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
String label = app.loadLabel(pm).toString();
|
||||
// Load the icon and convert it into a bitmap.
|
||||
Drawable icon = app.loadIcon(pm);
|
||||
Bitmap bitmap = null;
|
||||
if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) {
|
||||
int width = mContext.getResources().getDimensionPixelSize(
|
||||
android.R.dimen.notification_large_icon_width);
|
||||
int height = mContext.getResources().getDimensionPixelSize(
|
||||
android.R.dimen.notification_large_icon_height);
|
||||
icon.setBounds(0, 0, width, height);
|
||||
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
Canvas c = new Canvas(bitmap);
|
||||
icon.draw(c);
|
||||
c.setBitmap(null);
|
||||
}
|
||||
showNotification(label, bitmap, user);
|
||||
} else {
|
||||
showNotification(null, null, user);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeVpnUserLocked(int user) {
|
||||
@@ -584,7 +578,6 @@ public class Vpn {
|
||||
mNetworkAgent.removeUidRanges(new UidRange[] { uidRange });
|
||||
}
|
||||
mVpnUsers.remove(uidRange);
|
||||
hideNotification(user);
|
||||
}
|
||||
|
||||
private void onUserAdded(int userId) {
|
||||
@@ -652,9 +645,6 @@ public class Vpn {
|
||||
public void interfaceRemoved(String interfaze) {
|
||||
synchronized (Vpn.this) {
|
||||
if (interfaze.equals(mInterface) && jniCheck(interfaze) == 0) {
|
||||
for (UidRange uidRange : mVpnUsers) {
|
||||
hideNotification(uidRange.getStartUser());
|
||||
}
|
||||
mVpnUsers = null;
|
||||
mInterface = null;
|
||||
if (mConnection != null) {
|
||||
@@ -712,56 +702,6 @@ public class Vpn {
|
||||
}
|
||||
}
|
||||
|
||||
private void showNotification(String label, Bitmap icon, int user) {
|
||||
if (!mEnableNotif) return;
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mStatusIntent = VpnConfig.getIntentForStatusPanel(mContext);
|
||||
|
||||
NotificationManager nm = (NotificationManager)
|
||||
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
if (nm != null) {
|
||||
String title = (label == null) ? mContext.getString(R.string.vpn_title) :
|
||||
mContext.getString(R.string.vpn_title_long, label);
|
||||
String text = (mConfig.session == null) ? mContext.getString(R.string.vpn_text) :
|
||||
mContext.getString(R.string.vpn_text_long, mConfig.session);
|
||||
|
||||
Notification notification = new Notification.Builder(mContext)
|
||||
.setSmallIcon(R.drawable.vpn_connected)
|
||||
.setLargeIcon(icon)
|
||||
.setContentTitle(title)
|
||||
.setContentText(text)
|
||||
.setContentIntent(mStatusIntent)
|
||||
.setDefaults(0)
|
||||
.setOngoing(true)
|
||||
.setColor(mContext.getResources().getColor(
|
||||
com.android.internal.R.color.system_notification_accent_color))
|
||||
.build();
|
||||
nm.notifyAsUser(null, R.drawable.vpn_connected, notification, new UserHandle(user));
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
|
||||
private void hideNotification(int user) {
|
||||
if (!mEnableNotif) return;
|
||||
mStatusIntent = null;
|
||||
|
||||
NotificationManager nm = (NotificationManager)
|
||||
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
if (nm != null) {
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
nm.cancelAsUser(null, R.drawable.vpn_connected, new UserHandle(user));
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean addAddress(String address, int prefixLength) {
|
||||
if (Binder.getCallingUid() != mOwnerUID || mInterface == null || mNetworkAgent == null) {
|
||||
return false;
|
||||
@@ -971,9 +911,6 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +205,6 @@ public class LockdownVpnTracker {
|
||||
private void initLocked() {
|
||||
Slog.d(TAG, "initLocked()");
|
||||
|
||||
mVpn.setEnableNotifications(false);
|
||||
mVpn.setEnableTeardown(false);
|
||||
|
||||
final IntentFilter resetFilter = new IntentFilter(ACTION_LOCKDOWN_RESET);
|
||||
@@ -249,7 +248,6 @@ public class LockdownVpnTracker {
|
||||
hideNotification();
|
||||
|
||||
mContext.unregisterReceiver(mResetReceiver);
|
||||
mVpn.setEnableNotifications(true);
|
||||
mVpn.setEnableTeardown(true);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user