1 /*
2  * Copyright (C) 2017 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.vpndialogs;
18 
19 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
20 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
21 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
22 
23 import android.content.Context;
24 import android.content.DialogInterface;
25 import android.content.Intent;
26 import android.content.pm.PackageManager;
27 import android.net.IConnectivityManager;
28 import android.os.Bundle;
29 import android.os.RemoteException;
30 import android.os.ServiceManager;
31 import android.os.UserHandle;
32 import android.provider.Settings;
33 import android.text.SpannableStringBuilder;
34 import android.text.method.LinkMovementMethod;
35 import android.text.style.ClickableSpan;
36 import android.util.Log;
37 import android.view.View;
38 import android.widget.TextView;
39 
40 import com.android.internal.app.AlertActivity;
41 import com.android.internal.net.VpnConfig;
42 
43 public class AlwaysOnDisconnectedDialog extends AlertActivity
44         implements DialogInterface.OnClickListener{
45 
46     private static final String TAG = "VpnDisconnected";
47 
48     private IConnectivityManager mService;
49     private int mUserId;
50     private String mVpnPackage;
51 
52     @Override
onCreate(Bundle savedInstanceState)53     public void onCreate(Bundle savedInstanceState) {
54         super.onCreate(savedInstanceState);
55 
56         mService = IConnectivityManager.Stub.asInterface(
57                 ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
58         mUserId = UserHandle.myUserId();
59         mVpnPackage = getAlwaysOnVpnPackage();
60         if (mVpnPackage == null) {
61             finish();
62             return;
63         }
64 
65         View view = View.inflate(this, R.layout.always_on_disconnected, null);
66         TextView messageView = view.findViewById(R.id.message);
67         messageView.setText(getMessage(getIntent().getBooleanExtra("lockdown", false)));
68         messageView.setMovementMethod(LinkMovementMethod.getInstance());
69 
70         mAlertParams.mTitle = getString(R.string.always_on_disconnected_title);
71         mAlertParams.mPositiveButtonText = getString(R.string.open_app);
72         mAlertParams.mPositiveButtonListener = this;
73         mAlertParams.mNegativeButtonText = getString(R.string.dismiss);
74         mAlertParams.mNegativeButtonListener = this;
75         mAlertParams.mCancelable = false;
76         mAlertParams.mView = view;
77         setupAlert();
78 
79         getWindow().setCloseOnTouchOutside(false);
80         getWindow().setType(TYPE_SYSTEM_ALERT);
81         getWindow().addFlags(FLAG_ALT_FOCUSABLE_IM);
82         getWindow().addPrivateFlags(SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
83     }
84 
85     @Override
onClick(DialogInterface dialog, int which)86     public void onClick(DialogInterface dialog, int which) {
87         switch (which) {
88             case BUTTON_POSITIVE:
89                 PackageManager pm = getPackageManager();
90                 final Intent intent = pm.getLaunchIntentForPackage(mVpnPackage);
91                 if (intent != null) {
92                     intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
93                     startActivity(intent);
94                 }
95                 finish();
96                 break;
97             case BUTTON_NEGATIVE:
98                 finish();
99                 break;
100             default:
101                 break;
102         }
103     }
104 
getAlwaysOnVpnPackage()105     private String getAlwaysOnVpnPackage() {
106         try {
107             return mService.getAlwaysOnVpnPackage(mUserId);
108         } catch (RemoteException e) {
109             Log.e(TAG, "Can't getAlwaysOnVpnPackage()", e);
110             return null;
111         }
112     }
113 
getVpnLabel()114     private CharSequence getVpnLabel() {
115         try {
116             return VpnConfig.getVpnLabel(this, mVpnPackage);
117         } catch (PackageManager.NameNotFoundException e) {
118             Log.w(TAG, "Can't getVpnLabel() for " + mVpnPackage, e);
119             return mVpnPackage;
120         }
121     }
122 
getMessage(boolean isLockdown)123     private CharSequence getMessage(boolean isLockdown) {
124         final SpannableStringBuilder message = new SpannableStringBuilder();
125         final int baseMessageResId = isLockdown
126                 ? R.string.always_on_disconnected_message_lockdown
127                 : R.string.always_on_disconnected_message;
128         message.append(getString(baseMessageResId, getVpnLabel()));
129         message.append(getString(R.string.always_on_disconnected_message_separator));
130         message.append(getString(R.string.always_on_disconnected_message_settings_link),
131                 new VpnSpan(), 0 /*flags*/);
132         return message;
133     }
134 
135     private class VpnSpan extends ClickableSpan {
136         @Override
onClick(View unused)137         public void onClick(View unused) {
138             final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS);
139             intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
140             startActivity(intent);
141         }
142     }
143 }
144