1 /*
2  * Copyright (C) 2014 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 package com.android.systemui.qs;
17 
18 import android.app.AlertDialog;
19 import android.content.Context;
20 import android.content.DialogInterface;
21 import android.content.Intent;
22 import android.os.Handler;
23 import android.os.Looper;
24 import android.os.Message;
25 import android.os.UserHandle;
26 import android.util.Log;
27 import android.view.LayoutInflater;
28 import android.view.View;
29 import android.view.View.OnClickListener;
30 import android.widget.ImageView;
31 import android.widget.TextView;
32 
33 import com.android.systemui.FontSizeUtils;
34 import com.android.systemui.R;
35 import com.android.systemui.statusbar.phone.QSTileHost;
36 import com.android.systemui.statusbar.phone.SystemUIDialog;
37 import com.android.systemui.statusbar.policy.SecurityController;
38 
39 public class QSFooter implements OnClickListener, DialogInterface.OnClickListener {
40     protected static final String TAG = "QSFooter";
41     protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
42 
43     private static final String ACTION_VPN_SETTINGS = "android.net.vpn.SETTINGS";
44 
45     private final View mRootView;
46     private final TextView mFooterText;
47     private final ImageView mFooterIcon;
48     private final Context mContext;
49     private final Callback mCallback = new Callback();
50 
51     private SecurityController mSecurityController;
52     private AlertDialog mDialog;
53     private QSTileHost mHost;
54     private Handler mHandler;
55     private final Handler mMainHandler;
56 
57     private boolean mIsVisible;
58     private boolean mIsIconVisible;
59     private int mFooterTextId;
60 
QSFooter(QSPanel qsPanel, Context context)61     public QSFooter(QSPanel qsPanel, Context context) {
62         mRootView = LayoutInflater.from(context)
63                 .inflate(R.layout.quick_settings_footer, qsPanel, false);
64         mRootView.setOnClickListener(this);
65         mFooterText = (TextView) mRootView.findViewById(R.id.footer_text);
66         mFooterIcon = (ImageView) mRootView.findViewById(R.id.footer_icon);
67         mContext = context;
68         mMainHandler = new Handler();
69     }
70 
setHost(QSTileHost host)71     public void setHost(QSTileHost host) {
72         mHost = host;
73         mSecurityController = host.getSecurityController();
74         mHandler = new H(host.getLooper());
75     }
76 
setListening(boolean listening)77     public void setListening(boolean listening) {
78         if (listening) {
79             mSecurityController.addCallback(mCallback);
80         } else {
81             mSecurityController.removeCallback(mCallback);
82         }
83     }
84 
onConfigurationChanged()85     public void onConfigurationChanged() {
86         FontSizeUtils.updateFontSize(mFooterText, R.dimen.qs_tile_text_size);
87     }
88 
getView()89     public View getView() {
90         return mRootView;
91     }
92 
hasFooter()93     public boolean hasFooter() {
94         return mRootView.getVisibility() != View.GONE;
95     }
96 
97     @Override
onClick(View v)98     public void onClick(View v) {
99         mHandler.sendEmptyMessage(H.CLICK);
100     }
101 
handleClick()102     private void handleClick() {
103         mHost.collapsePanels();
104         // TODO: Delay dialog creation until after panels are collapsed.
105         createDialog();
106     }
107 
refreshState()108     public void refreshState() {
109         mHandler.sendEmptyMessage(H.REFRESH_STATE);
110     }
111 
handleRefreshState()112     private void handleRefreshState() {
113         mIsIconVisible = mSecurityController.isVpnEnabled();
114         if (mSecurityController.hasDeviceOwner()) {
115             mFooterTextId = R.string.device_owned_footer;
116             mIsVisible = true;
117         } else {
118             mFooterTextId = R.string.vpn_footer;
119             mIsVisible = mIsIconVisible;
120         }
121         mMainHandler.post(mUpdateDisplayState);
122     }
123 
124     @Override
onClick(DialogInterface dialog, int which)125     public void onClick(DialogInterface dialog, int which) {
126         if (which == DialogInterface.BUTTON_NEGATIVE) {
127             final Intent settingsIntent = new Intent(ACTION_VPN_SETTINGS);
128             mContext.startActivityAsUser(settingsIntent, UserHandle.CURRENT);
129         }
130     }
131 
createDialog()132     private void createDialog() {
133         String deviceOwner = mSecurityController.getDeviceOwnerName();
134         String profileOwner = mSecurityController.getProfileOwnerName();
135         String primaryVpn = mSecurityController.getPrimaryVpnName();
136         String profileVpn = mSecurityController.getProfileVpnName();
137         boolean managed = mSecurityController.hasProfileOwner();
138 
139         mDialog = new SystemUIDialog(mContext);
140         mDialog.setTitle(getTitle(deviceOwner));
141         mDialog.setMessage(getMessage(deviceOwner, profileOwner, primaryVpn, profileVpn, managed));
142         mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
143         if (mSecurityController.isVpnEnabled()) {
144             mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getNegativeButton(), this);
145         }
146         mDialog.show();
147     }
148 
getNegativeButton()149     private String getNegativeButton() {
150         return mContext.getString(R.string.status_bar_settings_settings_button);
151     }
152 
getPositiveButton()153     private String getPositiveButton() {
154         return mContext.getString(R.string.quick_settings_done);
155     }
156 
getMessage(String deviceOwner, String profileOwner, String primaryVpn, String profileVpn, boolean primaryUserIsManaged)157     private String getMessage(String deviceOwner, String profileOwner, String primaryVpn,
158             String profileVpn, boolean primaryUserIsManaged) {
159         if (deviceOwner != null) {
160             if (primaryVpn != null) {
161                 return mContext.getString(R.string.monitoring_description_vpn_app_device_owned,
162                         deviceOwner, primaryVpn);
163             } else {
164                 return mContext.getString(R.string.monitoring_description_device_owned,
165                         deviceOwner);
166             }
167         } else if (primaryVpn != null) {
168             if (profileVpn != null) {
169                 return mContext.getString(R.string.monitoring_description_app_personal_work,
170                         profileOwner, profileVpn, primaryVpn);
171             } else {
172                 return mContext.getString(R.string.monitoring_description_app_personal,
173                         primaryVpn);
174             }
175         } else if (profileVpn != null) {
176             return mContext.getString(R.string.monitoring_description_app_work,
177                     profileOwner, profileVpn);
178         } else if (profileOwner != null && primaryUserIsManaged) {
179             return mContext.getString(R.string.monitoring_description_device_owned,
180                     profileOwner);
181         } else {
182             // No device owner, no personal VPN, no work VPN, no user owner. Why are we here?
183             return null;
184         }
185     }
186 
getTitle(String deviceOwner)187     private int getTitle(String deviceOwner) {
188         if (deviceOwner != null) {
189             return R.string.monitoring_title_device_owned;
190         } else {
191             return R.string.monitoring_title;
192         }
193     }
194 
195     private final Runnable mUpdateDisplayState = new Runnable() {
196         @Override
197         public void run() {
198             if (mFooterTextId != 0) {
199                 mFooterText.setText(mFooterTextId);
200             }
201             mRootView.setVisibility(mIsVisible ? View.VISIBLE : View.GONE);
202             mFooterIcon.setVisibility(mIsIconVisible ? View.VISIBLE : View.INVISIBLE);
203         }
204     };
205 
206     private class Callback implements SecurityController.SecurityControllerCallback {
207         @Override
onStateChanged()208         public void onStateChanged() {
209             refreshState();
210         }
211     }
212 
213     private class H extends Handler {
214         private static final int CLICK = 0;
215         private static final int REFRESH_STATE = 1;
216 
H(Looper looper)217         private H(Looper looper) {
218             super(looper);
219         }
220 
221         @Override
handleMessage(Message msg)222         public void handleMessage(Message msg) {
223             String name = null;
224             try {
225                 if (msg.what == REFRESH_STATE) {
226                     name = "handleRefreshState";
227                     handleRefreshState();
228                 } else if (msg.what == CLICK) {
229                     name = "handleClick";
230                     handleClick();
231                 }
232             } catch (Throwable t) {
233                 final String error = "Error in " + name;
234                 Log.w(TAG, error, t);
235                 mHost.warn(error, t);
236             }
237         }
238     }
239 
240 }
241