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