| /* |
| * Copyright (C) 2014 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.systemui.qs; |
| |
| import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED; |
| import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; |
| import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; |
| |
| import static com.android.systemui.qs.dagger.QSFragmentModule.QS_SECURITY_FOOTER_VIEW; |
| |
| import android.app.AlertDialog; |
| import android.app.admin.DeviceAdminInfo; |
| import android.app.admin.DevicePolicyEventLogger; |
| import android.content.Context; |
| import android.content.DialogInterface; |
| import android.content.Intent; |
| import android.content.pm.UserInfo; |
| import android.content.res.Configuration; |
| import android.content.res.Resources; |
| import android.graphics.drawable.Drawable; |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.os.Message; |
| import android.os.UserManager; |
| import android.provider.Settings; |
| import android.text.SpannableStringBuilder; |
| import android.text.method.LinkMovementMethod; |
| import android.text.style.ClickableSpan; |
| import android.util.Log; |
| import android.view.LayoutInflater; |
| import android.view.View; |
| import android.view.View.OnClickListener; |
| import android.view.ViewGroup; |
| import android.view.Window; |
| import android.widget.ImageView; |
| import android.widget.TextView; |
| |
| import androidx.annotation.VisibleForTesting; |
| |
| import com.android.internal.util.FrameworkStatsLog; |
| import com.android.systemui.FontSizeUtils; |
| import com.android.systemui.R; |
| import com.android.systemui.dagger.qualifiers.Background; |
| import com.android.systemui.dagger.qualifiers.Main; |
| import com.android.systemui.plugins.ActivityStarter; |
| import com.android.systemui.qs.dagger.QSScope; |
| import com.android.systemui.settings.UserTracker; |
| import com.android.systemui.statusbar.phone.SystemUIDialog; |
| import com.android.systemui.statusbar.policy.SecurityController; |
| |
| import javax.inject.Inject; |
| import javax.inject.Named; |
| |
| @QSScope |
| class QSSecurityFooter implements OnClickListener, DialogInterface.OnClickListener { |
| protected static final String TAG = "QSSecurityFooter"; |
| protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); |
| private static final boolean DEBUG_FORCE_VISIBLE = false; |
| |
| private final View mRootView; |
| private final TextView mFooterText; |
| private final ImageView mPrimaryFooterIcon; |
| private final Context mContext; |
| private final Callback mCallback = new Callback(); |
| private final SecurityController mSecurityController; |
| private final ActivityStarter mActivityStarter; |
| private final Handler mMainHandler; |
| private final UserTracker mUserTracker; |
| |
| private AlertDialog mDialog; |
| private QSTileHost mHost; |
| protected H mHandler; |
| |
| private boolean mIsVisible; |
| private CharSequence mFooterTextContent = null; |
| private int mFooterIconId; |
| private Drawable mPrimaryFooterIconDrawable; |
| |
| @Inject |
| QSSecurityFooter(@Named(QS_SECURITY_FOOTER_VIEW) View rootView, |
| UserTracker userTracker, @Main Handler mainHandler, ActivityStarter activityStarter, |
| SecurityController securityController, @Background Looper bgLooper) { |
| mRootView = rootView; |
| mRootView.setOnClickListener(this); |
| mFooterText = mRootView.findViewById(R.id.footer_text); |
| mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon); |
| mFooterIconId = R.drawable.ic_info_outline; |
| mContext = rootView.getContext(); |
| mMainHandler = mainHandler; |
| mActivityStarter = activityStarter; |
| mSecurityController = securityController; |
| mHandler = new H(bgLooper); |
| mUserTracker = userTracker; |
| } |
| |
| public void setHostEnvironment(QSTileHost host) { |
| mHost = host; |
| } |
| |
| public void setListening(boolean listening) { |
| if (listening) { |
| mSecurityController.addCallback(mCallback); |
| refreshState(); |
| } else { |
| mSecurityController.removeCallback(mCallback); |
| } |
| } |
| |
| public void onConfigurationChanged() { |
| FontSizeUtils.updateFontSize(mFooterText, R.dimen.qs_tile_text_size); |
| |
| Resources r = mContext.getResources(); |
| |
| mFooterText.setMaxLines(r.getInteger(R.integer.qs_security_footer_maxLines)); |
| int padding = r.getDimensionPixelSize(R.dimen.qs_footer_padding); |
| mRootView.setPaddingRelative(padding, padding, padding, padding); |
| |
| int bottomMargin = r.getDimensionPixelSize(R.dimen.qs_footers_margin_bottom); |
| ViewGroup.MarginLayoutParams lp = |
| (ViewGroup.MarginLayoutParams) mRootView.getLayoutParams(); |
| lp.bottomMargin = bottomMargin; |
| lp.width = r.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT |
| ? MATCH_PARENT : WRAP_CONTENT; |
| mRootView.setLayoutParams(lp); |
| |
| mRootView.setBackground(mContext.getDrawable(R.drawable.qs_security_footer_background)); |
| } |
| |
| public View getView() { |
| return mRootView; |
| } |
| |
| public boolean hasFooter() { |
| return mRootView.getVisibility() != View.GONE; |
| } |
| |
| @Override |
| public void onClick(View v) { |
| if (!hasFooter()) return; |
| mHandler.sendEmptyMessage(H.CLICK); |
| } |
| |
| private void handleClick() { |
| showDeviceMonitoringDialog(); |
| DevicePolicyEventLogger |
| .createEvent(FrameworkStatsLog.DEVICE_POLICY_EVENT__EVENT_ID__DO_USER_INFO_CLICKED) |
| .write(); |
| } |
| |
| public void showDeviceMonitoringDialog() { |
| createDialog(); |
| } |
| |
| public void refreshState() { |
| mHandler.sendEmptyMessage(H.REFRESH_STATE); |
| } |
| |
| private void handleRefreshState() { |
| final boolean isDeviceManaged = mSecurityController.isDeviceManaged(); |
| final UserInfo currentUser = mUserTracker.getUserInfo(); |
| final boolean isDemoDevice = UserManager.isDeviceInDemoMode(mContext) && currentUser != null |
| && currentUser.isDemo(); |
| final boolean hasWorkProfile = mSecurityController.hasWorkProfile(); |
| final boolean hasCACerts = mSecurityController.hasCACertInCurrentUser(); |
| final boolean hasCACertsInWorkProfile = mSecurityController.hasCACertInWorkProfile(); |
| final boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled(); |
| final String vpnName = mSecurityController.getPrimaryVpnName(); |
| final String vpnNameWorkProfile = mSecurityController.getWorkProfileVpnName(); |
| final CharSequence organizationName = mSecurityController.getDeviceOwnerOrganizationName(); |
| final CharSequence workProfileOrganizationName = |
| mSecurityController.getWorkProfileOrganizationName(); |
| final boolean isProfileOwnerOfOrganizationOwnedDevice = |
| mSecurityController.isProfileOwnerOfOrganizationOwnedDevice(); |
| final boolean isParentalControlsEnabled = mSecurityController.isParentalControlsEnabled(); |
| final boolean isWorkProfileOn = mSecurityController.isWorkProfileOn(); |
| final boolean hasDisclosableWorkProfilePolicy = hasCACertsInWorkProfile |
| || vpnNameWorkProfile != null || (hasWorkProfile && isNetworkLoggingEnabled); |
| // Update visibility of footer |
| mIsVisible = (isDeviceManaged && !isDemoDevice) |
| || hasCACerts |
| || vpnName != null |
| || isProfileOwnerOfOrganizationOwnedDevice |
| || isParentalControlsEnabled |
| || (hasDisclosableWorkProfilePolicy && isWorkProfileOn); |
| // Update the view to be untappable if the device is an organization-owned device with a |
| // managed profile and there is either: |
| // a) no policy set which requires a privacy disclosure. |
| // b) a specific work policy set but the work profile is turned off. |
| if (mIsVisible && isProfileOwnerOfOrganizationOwnedDevice |
| && (!hasDisclosableWorkProfilePolicy || !isWorkProfileOn)) { |
| mRootView.setClickable(false); |
| mRootView.findViewById(R.id.footer_icon).setVisibility(View.GONE); |
| } else { |
| mRootView.setClickable(true); |
| mRootView.findViewById(R.id.footer_icon).setVisibility(View.VISIBLE); |
| } |
| // Update the string |
| mFooterTextContent = getFooterText(isDeviceManaged, hasWorkProfile, |
| hasCACerts, hasCACertsInWorkProfile, isNetworkLoggingEnabled, vpnName, |
| vpnNameWorkProfile, organizationName, workProfileOrganizationName, |
| isProfileOwnerOfOrganizationOwnedDevice, isParentalControlsEnabled, |
| isWorkProfileOn); |
| // Update the icon |
| int footerIconId = R.drawable.ic_info_outline; |
| if (vpnName != null || vpnNameWorkProfile != null) { |
| if (mSecurityController.isVpnBranded()) { |
| footerIconId = R.drawable.stat_sys_branded_vpn; |
| } else { |
| footerIconId = R.drawable.stat_sys_vpn_ic; |
| } |
| } |
| if (mFooterIconId != footerIconId) { |
| mFooterIconId = footerIconId; |
| } |
| |
| // Update the primary icon |
| if (isParentalControlsEnabled) { |
| if (mPrimaryFooterIconDrawable == null) { |
| DeviceAdminInfo info = mSecurityController.getDeviceAdminInfo(); |
| mPrimaryFooterIconDrawable = mSecurityController.getIcon(info); |
| } |
| } else { |
| mPrimaryFooterIconDrawable = null; |
| } |
| mMainHandler.post(mUpdatePrimaryIcon); |
| |
| mMainHandler.post(mUpdateDisplayState); |
| } |
| |
| protected CharSequence getFooterText(boolean isDeviceManaged, boolean hasWorkProfile, |
| boolean hasCACerts, boolean hasCACertsInWorkProfile, boolean isNetworkLoggingEnabled, |
| String vpnName, String vpnNameWorkProfile, CharSequence organizationName, |
| CharSequence workProfileOrganizationName, |
| boolean isProfileOwnerOfOrganizationOwnedDevice, boolean isParentalControlsEnabled, |
| boolean isWorkProfileOn) { |
| if (isParentalControlsEnabled) { |
| return mContext.getString(R.string.quick_settings_disclosure_parental_controls); |
| } |
| if (isDeviceManaged || DEBUG_FORCE_VISIBLE) { |
| if (hasCACerts || hasCACertsInWorkProfile || isNetworkLoggingEnabled) { |
| if (organizationName == null) { |
| return mContext.getString( |
| R.string.quick_settings_disclosure_management_monitoring); |
| } |
| return mContext.getString( |
| R.string.quick_settings_disclosure_named_management_monitoring, |
| organizationName); |
| } |
| if (vpnName != null && vpnNameWorkProfile != null) { |
| if (organizationName == null) { |
| return mContext.getString(R.string.quick_settings_disclosure_management_vpns); |
| } |
| return mContext.getString(R.string.quick_settings_disclosure_named_management_vpns, |
| organizationName); |
| } |
| if (vpnName != null || vpnNameWorkProfile != null) { |
| if (organizationName == null) { |
| return mContext.getString( |
| R.string.quick_settings_disclosure_management_named_vpn, |
| vpnName != null ? vpnName : vpnNameWorkProfile); |
| } |
| return mContext.getString( |
| R.string.quick_settings_disclosure_named_management_named_vpn, |
| organizationName, |
| vpnName != null ? vpnName : vpnNameWorkProfile); |
| } |
| if (organizationName == null) { |
| return mContext.getString(R.string.quick_settings_disclosure_management); |
| } |
| if (isFinancedDevice()) { |
| return mContext.getString( |
| R.string.quick_settings_financed_disclosure_named_management, |
| organizationName); |
| } else { |
| return mContext.getString(R.string.quick_settings_disclosure_named_management, |
| organizationName); |
| } |
| } // end if(isDeviceManaged) |
| if (hasCACertsInWorkProfile && isWorkProfileOn) { |
| if (workProfileOrganizationName == null) { |
| return mContext.getString( |
| R.string.quick_settings_disclosure_managed_profile_monitoring); |
| } |
| return mContext.getString( |
| R.string.quick_settings_disclosure_named_managed_profile_monitoring, |
| workProfileOrganizationName); |
| } |
| if (hasCACerts) { |
| return mContext.getString(R.string.quick_settings_disclosure_monitoring); |
| } |
| if (vpnName != null && vpnNameWorkProfile != null) { |
| return mContext.getString(R.string.quick_settings_disclosure_vpns); |
| } |
| if (vpnNameWorkProfile != null && isWorkProfileOn) { |
| return mContext.getString(R.string.quick_settings_disclosure_managed_profile_named_vpn, |
| vpnNameWorkProfile); |
| } |
| if (vpnName != null) { |
| if (hasWorkProfile) { |
| return mContext.getString( |
| R.string.quick_settings_disclosure_personal_profile_named_vpn, |
| vpnName); |
| } |
| return mContext.getString(R.string.quick_settings_disclosure_named_vpn, |
| vpnName); |
| } |
| if (hasWorkProfile && isNetworkLoggingEnabled && isWorkProfileOn) { |
| return mContext.getString( |
| R.string.quick_settings_disclosure_managed_profile_network_activity); |
| } |
| if (isProfileOwnerOfOrganizationOwnedDevice) { |
| if (workProfileOrganizationName == null) { |
| return mContext.getString(R.string.quick_settings_disclosure_management); |
| } |
| return mContext.getString(R.string.quick_settings_disclosure_named_management, |
| workProfileOrganizationName); |
| } |
| return null; |
| } |
| |
| @Override |
| public void onClick(DialogInterface dialog, int which) { |
| if (which == DialogInterface.BUTTON_NEGATIVE) { |
| final Intent intent = new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS); |
| mDialog.dismiss(); |
| // This dismisses the shade on opening the activity |
| mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); |
| } |
| } |
| |
| private void createDialog() { |
| mDialog = new SystemUIDialog(mContext, 0); // Use mContext theme |
| mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE); |
| mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this); |
| mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getNegativeButton(), this); |
| |
| mDialog.setView(createDialogView()); |
| |
| mDialog.show(); |
| mDialog.getWindow().setLayout(MATCH_PARENT, |
| ViewGroup.LayoutParams.WRAP_CONTENT); |
| } |
| |
| @VisibleForTesting |
| View createDialogView() { |
| if (mSecurityController.isParentalControlsEnabled()) { |
| return createParentalControlsDialogView(); |
| } |
| return createOrganizationDialogView(); |
| } |
| |
| private View createOrganizationDialogView() { |
| final boolean isDeviceManaged = mSecurityController.isDeviceManaged(); |
| final boolean hasWorkProfile = mSecurityController.hasWorkProfile(); |
| final CharSequence deviceOwnerOrganization = |
| mSecurityController.getDeviceOwnerOrganizationName(); |
| final boolean hasCACerts = mSecurityController.hasCACertInCurrentUser(); |
| final boolean hasCACertsInWorkProfile = mSecurityController.hasCACertInWorkProfile(); |
| final boolean isNetworkLoggingEnabled = mSecurityController.isNetworkLoggingEnabled(); |
| final String vpnName = mSecurityController.getPrimaryVpnName(); |
| final String vpnNameWorkProfile = mSecurityController.getWorkProfileVpnName(); |
| |
| View dialogView = LayoutInflater.from(mContext) |
| .inflate(R.layout.quick_settings_footer_dialog, null, false); |
| |
| // device management section |
| TextView deviceManagementSubtitle = |
| dialogView.findViewById(R.id.device_management_subtitle); |
| deviceManagementSubtitle.setText(getManagementTitle(deviceOwnerOrganization)); |
| |
| CharSequence managementMessage = getManagementMessage(isDeviceManaged, |
| deviceOwnerOrganization); |
| if (managementMessage == null) { |
| dialogView.findViewById(R.id.device_management_disclosures).setVisibility(View.GONE); |
| } else { |
| dialogView.findViewById(R.id.device_management_disclosures).setVisibility(View.VISIBLE); |
| TextView deviceManagementWarning = |
| (TextView) dialogView.findViewById(R.id.device_management_warning); |
| deviceManagementWarning.setText(managementMessage); |
| mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, getSettingsButton(), this); |
| } |
| |
| // ca certificate section |
| CharSequence caCertsMessage = getCaCertsMessage(isDeviceManaged, hasCACerts, |
| hasCACertsInWorkProfile); |
| if (caCertsMessage == null) { |
| dialogView.findViewById(R.id.ca_certs_disclosures).setVisibility(View.GONE); |
| } else { |
| dialogView.findViewById(R.id.ca_certs_disclosures).setVisibility(View.VISIBLE); |
| TextView caCertsWarning = (TextView) dialogView.findViewById(R.id.ca_certs_warning); |
| caCertsWarning.setText(caCertsMessage); |
| // Make "Open trusted credentials"-link clickable |
| caCertsWarning.setMovementMethod(new LinkMovementMethod()); |
| } |
| |
| // network logging section |
| CharSequence networkLoggingMessage = getNetworkLoggingMessage(isDeviceManaged, |
| isNetworkLoggingEnabled); |
| if (networkLoggingMessage == null) { |
| dialogView.findViewById(R.id.network_logging_disclosures).setVisibility(View.GONE); |
| } else { |
| dialogView.findViewById(R.id.network_logging_disclosures).setVisibility(View.VISIBLE); |
| TextView networkLoggingWarning = |
| (TextView) dialogView.findViewById(R.id.network_logging_warning); |
| networkLoggingWarning.setText(networkLoggingMessage); |
| } |
| |
| // vpn section |
| CharSequence vpnMessage = getVpnMessage(isDeviceManaged, hasWorkProfile, vpnName, |
| vpnNameWorkProfile); |
| if (vpnMessage == null) { |
| dialogView.findViewById(R.id.vpn_disclosures).setVisibility(View.GONE); |
| } else { |
| dialogView.findViewById(R.id.vpn_disclosures).setVisibility(View.VISIBLE); |
| TextView vpnWarning = (TextView) dialogView.findViewById(R.id.vpn_warning); |
| vpnWarning.setText(vpnMessage); |
| // Make "Open VPN Settings"-link clickable |
| vpnWarning.setMovementMethod(new LinkMovementMethod()); |
| } |
| |
| // Note: if a new section is added, should update configSubtitleVisibility to include |
| // the handling of the subtitle |
| configSubtitleVisibility(managementMessage != null, |
| caCertsMessage != null, |
| networkLoggingMessage != null, |
| vpnMessage != null, |
| dialogView); |
| |
| return dialogView; |
| } |
| |
| private View createParentalControlsDialogView() { |
| View dialogView = LayoutInflater.from(mContext) |
| .inflate(R.layout.quick_settings_footer_dialog_parental_controls, null, false); |
| |
| DeviceAdminInfo info = mSecurityController.getDeviceAdminInfo(); |
| Drawable icon = mSecurityController.getIcon(info); |
| if (icon != null) { |
| ImageView imageView = (ImageView) dialogView.findViewById(R.id.parental_controls_icon); |
| imageView.setImageDrawable(icon); |
| } |
| |
| TextView parentalControlsTitle = |
| (TextView) dialogView.findViewById(R.id.parental_controls_title); |
| parentalControlsTitle.setText(mSecurityController.getLabel(info)); |
| |
| return dialogView; |
| } |
| |
| protected void configSubtitleVisibility(boolean showDeviceManagement, boolean showCaCerts, |
| boolean showNetworkLogging, boolean showVpn, View dialogView) { |
| // Device Management title should always been shown |
| // When there is a Device Management message, all subtitles should be shown |
| if (showDeviceManagement) { |
| return; |
| } |
| // Hide the subtitle if there is only 1 message shown |
| int mSectionCountExcludingDeviceMgt = 0; |
| if (showCaCerts) { mSectionCountExcludingDeviceMgt++; } |
| if (showNetworkLogging) { mSectionCountExcludingDeviceMgt++; } |
| if (showVpn) { mSectionCountExcludingDeviceMgt++; } |
| |
| // No work needed if there is no sections or more than 1 section |
| if (mSectionCountExcludingDeviceMgt != 1) { |
| return; |
| } |
| if (showCaCerts) { |
| dialogView.findViewById(R.id.ca_certs_subtitle).setVisibility(View.GONE); |
| } |
| if (showNetworkLogging) { |
| dialogView.findViewById(R.id.network_logging_subtitle).setVisibility(View.GONE); |
| } |
| if (showVpn) { |
| dialogView.findViewById(R.id.vpn_subtitle).setVisibility(View.GONE); |
| } |
| } |
| |
| @VisibleForTesting |
| String getSettingsButton() { |
| return mContext.getString(R.string.monitoring_button_view_policies); |
| } |
| |
| private String getPositiveButton() { |
| return mContext.getString(R.string.ok); |
| } |
| |
| private String getNegativeButton() { |
| if (mSecurityController.isParentalControlsEnabled()) { |
| return mContext.getString(R.string.monitoring_button_view_controls); |
| } |
| return null; |
| } |
| |
| protected CharSequence getManagementMessage(boolean isDeviceManaged, |
| CharSequence organizationName) { |
| if (!isDeviceManaged) { |
| return null; |
| } |
| if (organizationName != null) { |
| if (isFinancedDevice()) { |
| return mContext.getString(R.string.monitoring_financed_description_named_management, |
| organizationName, organizationName); |
| } else { |
| return mContext.getString( |
| R.string.monitoring_description_named_management, organizationName); |
| } |
| } |
| return mContext.getString(R.string.monitoring_description_management); |
| } |
| |
| protected CharSequence getCaCertsMessage(boolean isDeviceManaged, boolean hasCACerts, |
| boolean hasCACertsInWorkProfile) { |
| if (!(hasCACerts || hasCACertsInWorkProfile)) return null; |
| if (isDeviceManaged) { |
| return mContext.getString(R.string.monitoring_description_management_ca_certificate); |
| } |
| if (hasCACertsInWorkProfile) { |
| return mContext.getString( |
| R.string.monitoring_description_managed_profile_ca_certificate); |
| } |
| return mContext.getString(R.string.monitoring_description_ca_certificate); |
| } |
| |
| protected CharSequence getNetworkLoggingMessage(boolean isDeviceManaged, |
| boolean isNetworkLoggingEnabled) { |
| if (!isNetworkLoggingEnabled) return null; |
| if (isDeviceManaged) { |
| return mContext.getString(R.string.monitoring_description_management_network_logging); |
| } else { |
| return mContext.getString( |
| R.string.monitoring_description_managed_profile_network_logging); |
| } |
| } |
| |
| protected CharSequence getVpnMessage(boolean isDeviceManaged, boolean hasWorkProfile, |
| String vpnName, String vpnNameWorkProfile) { |
| if (vpnName == null && vpnNameWorkProfile == null) return null; |
| final SpannableStringBuilder message = new SpannableStringBuilder(); |
| if (isDeviceManaged) { |
| if (vpnName != null && vpnNameWorkProfile != null) { |
| message.append(mContext.getString(R.string.monitoring_description_two_named_vpns, |
| vpnName, vpnNameWorkProfile)); |
| } else { |
| message.append(mContext.getString(R.string.monitoring_description_named_vpn, |
| vpnName != null ? vpnName : vpnNameWorkProfile)); |
| } |
| } else { |
| if (vpnName != null && vpnNameWorkProfile != null) { |
| message.append(mContext.getString(R.string.monitoring_description_two_named_vpns, |
| vpnName, vpnNameWorkProfile)); |
| } else if (vpnNameWorkProfile != null) { |
| message.append(mContext.getString( |
| R.string.monitoring_description_managed_profile_named_vpn, |
| vpnNameWorkProfile)); |
| } else if (hasWorkProfile) { |
| message.append(mContext.getString( |
| R.string.monitoring_description_personal_profile_named_vpn, vpnName)); |
| } else { |
| message.append(mContext.getString(R.string.monitoring_description_named_vpn, |
| vpnName)); |
| } |
| } |
| message.append(mContext.getString(R.string.monitoring_description_vpn_settings_separator)); |
| message.append(mContext.getString(R.string.monitoring_description_vpn_settings), |
| new VpnSpan(), 0); |
| return message; |
| } |
| |
| @VisibleForTesting |
| CharSequence getManagementTitle(CharSequence deviceOwnerOrganization) { |
| if (deviceOwnerOrganization != null && isFinancedDevice()) { |
| return mContext.getString(R.string.monitoring_title_financed_device, |
| deviceOwnerOrganization); |
| } else { |
| return mContext.getString(R.string.monitoring_title_device_owned); |
| } |
| } |
| |
| private boolean isFinancedDevice() { |
| return mSecurityController.isDeviceManaged() |
| && mSecurityController.getDeviceOwnerType( |
| mSecurityController.getDeviceOwnerComponentOnAnyUser()) |
| == DEVICE_OWNER_TYPE_FINANCED; |
| } |
| |
| private final Runnable mUpdatePrimaryIcon = new Runnable() { |
| @Override |
| public void run() { |
| if (mPrimaryFooterIconDrawable != null) { |
| mPrimaryFooterIcon.setImageDrawable(mPrimaryFooterIconDrawable); |
| } else { |
| mPrimaryFooterIcon.setImageResource(mFooterIconId); |
| } |
| } |
| }; |
| |
| private final Runnable mUpdateDisplayState = new Runnable() { |
| @Override |
| public void run() { |
| if (mFooterTextContent != null) { |
| mFooterText.setText(mFooterTextContent); |
| } |
| mRootView.setVisibility(mIsVisible || DEBUG_FORCE_VISIBLE ? View.VISIBLE : View.GONE); |
| } |
| }; |
| |
| private class Callback implements SecurityController.SecurityControllerCallback { |
| @Override |
| public void onStateChanged() { |
| refreshState(); |
| } |
| } |
| |
| private class H extends Handler { |
| private static final int CLICK = 0; |
| private static final int REFRESH_STATE = 1; |
| |
| private H(Looper looper) { |
| super(looper); |
| } |
| |
| @Override |
| public void handleMessage(Message msg) { |
| String name = null; |
| try { |
| if (msg.what == REFRESH_STATE) { |
| name = "handleRefreshState"; |
| handleRefreshState(); |
| } else if (msg.what == CLICK) { |
| name = "handleClick"; |
| handleClick(); |
| } |
| } catch (Throwable t) { |
| final String error = "Error in " + name; |
| Log.w(TAG, error, t); |
| mHost.warn(error, t); |
| } |
| } |
| } |
| |
| protected class VpnSpan extends ClickableSpan { |
| @Override |
| public void onClick(View widget) { |
| final Intent intent = new Intent(Settings.ACTION_VPN_SETTINGS); |
| mDialog.dismiss(); |
| // This dismisses the shade on opening the activity |
| mActivityStarter.postStartActivityDismissingKeyguard(intent, 0); |
| } |
| |
| // for testing, to compare two CharSequences containing VpnSpans |
| @Override |
| public boolean equals(Object object) { |
| return object instanceof VpnSpan; |
| } |
| |
| @Override |
| public int hashCode() { |
| return 314159257; // prime |
| } |
| } |
| } |