blob: b70b94b009239f0f101e37ba71578b8785694b2e [file] [log] [blame]
/*
* 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.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_CA_CERT;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_NAMED_VPN;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_NETWORK;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_TITLE;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MONITORING_CA_CERT_SUBTITLE;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MONITORING_NETWORK_SUBTITLE;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_MONITORING_VPN_SUBTITLE;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_NAMED_MANAGEMENT;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_PERSONAL_PROFILE_NAMED_VPN;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_VIEW_POLICIES;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_WORK_PROFILE_CA_CERT;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_WORK_PROFILE_NAMED_VPN;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_DIALOG_WORK_PROFILE_NETWORK;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_MANAGEMENT;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_MANAGEMENT_MONITORING;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_MANAGEMENT_MULTIPLE_VPNS;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_MANAGEMENT_NAMED_VPN;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_MANAGEMENT;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_MANAGEMENT_MONITORING;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_MANAGEMENT_MULTIPLE_VPNS;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_MANAGEMENT_NAMED_VPN;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_NAMED_WORK_PROFILE_MONITORING;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_PERSONAL_PROFILE_NAMED_VPN;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_WORK_PROFILE_MONITORING;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_WORK_PROFILE_NAMED_VPN;
import static android.app.admin.DevicePolicyResources.Strings.SystemUi.QS_MSG_WORK_PROFILE_NETWORK;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.os.Looper;
import android.os.UserManager;
import android.provider.DeviceConfig;
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.Window;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.systemui.R;
import com.android.systemui.animation.DialogCuj;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.animation.Expandable;
import com.android.systemui.common.shared.model.ContentDescription;
import com.android.systemui.common.shared.model.Icon;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.Application;
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.footer.domain.model.SecurityButtonConfig;
import com.android.systemui.security.data.model.SecurityModel;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.phone.SystemUIDialog;
import com.android.systemui.statusbar.policy.SecurityController;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import javax.inject.Inject;
/** Helper class for the configuration of the QS security footer button. */
@SysUISingleton
public class QSSecurityFooterUtils implements DialogInterface.OnClickListener {
protected static final String TAG = "QSSecurityFooterUtils";
protected static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final boolean DEBUG_FORCE_VISIBLE = false;
private static final String INTERACTION_JANK_TAG = "managed_device_info";
@Application private Context mContext;
private final DevicePolicyManager mDpm;
private final SecurityController mSecurityController;
private final ActivityStarter mActivityStarter;
private final Handler mMainHandler;
private final UserTracker mUserTracker;
private final DialogLaunchAnimator mDialogLaunchAnimator;
private final AtomicBoolean mShouldUseSettingsButton = new AtomicBoolean(false);
protected Handler mBgHandler;
private AlertDialog mDialog;
private Supplier<String> mManagementTitleSupplier = () ->
mContext == null ? null : mContext.getString(R.string.monitoring_title_device_owned);
private Supplier<String> mManagementMessageSupplier = () ->
mContext == null ? null : mContext.getString(
R.string.quick_settings_disclosure_management);
private Supplier<String> mManagementMonitoringStringSupplier = () ->
mContext == null ? null : mContext.getString(
R.string.quick_settings_disclosure_management_monitoring);
private Supplier<String> mManagementMultipleVpnStringSupplier = () ->
mContext == null ? null : mContext.getString(
R.string.quick_settings_disclosure_management_vpns);
private Supplier<String> mWorkProfileMonitoringStringSupplier = () ->
mContext == null ? null : mContext.getString(
R.string.quick_settings_disclosure_managed_profile_monitoring);
private Supplier<String> mWorkProfileNetworkStringSupplier = () ->
mContext == null ? null : mContext.getString(
R.string.quick_settings_disclosure_managed_profile_network_activity);
private Supplier<String> mMonitoringSubtitleCaCertStringSupplier = () ->
mContext == null ? null : mContext.getString(
R.string.monitoring_subtitle_ca_certificate);
private Supplier<String> mMonitoringSubtitleNetworkStringSupplier = () ->
mContext == null ? null : mContext.getString(
R.string.monitoring_subtitle_network_logging);
private Supplier<String> mMonitoringSubtitleVpnStringSupplier = () ->
mContext == null ? null : mContext.getString(R.string.monitoring_subtitle_vpn);
private Supplier<String> mViewPoliciesButtonStringSupplier = () ->
mContext == null ? null : mContext.getString(R.string.monitoring_button_view_policies);
private Supplier<String> mManagementDialogStringSupplier = () ->
mContext == null ? null : mContext.getString(
R.string.monitoring_description_management);
private Supplier<String> mManagementDialogCaCertStringSupplier = () ->
mContext == null ? null : mContext.getString(
R.string.monitoring_description_management_ca_certificate);
private Supplier<String> mWorkProfileDialogCaCertStringSupplier = () ->
mContext == null ? null : mContext.getString(
R.string.monitoring_description_managed_profile_ca_certificate);
private Supplier<String> mManagementDialogNetworkStringSupplier = () ->
mContext == null ? null : mContext.getString(
R.string.monitoring_description_management_network_logging);
private Supplier<String> mWorkProfileDialogNetworkStringSupplier = () ->
mContext == null ? null : mContext.getString(
R.string.monitoring_description_managed_profile_network_logging);
@Inject
QSSecurityFooterUtils(
@Application Context context, DevicePolicyManager devicePolicyManager,
UserTracker userTracker, @Main Handler mainHandler, ActivityStarter activityStarter,
SecurityController securityController, @Background Looper bgLooper,
DialogLaunchAnimator dialogLaunchAnimator) {
mContext = context;
mDpm = devicePolicyManager;
mUserTracker = userTracker;
mMainHandler = mainHandler;
mActivityStarter = activityStarter;
mSecurityController = securityController;
mBgHandler = new Handler(bgLooper);
mDialogLaunchAnimator = dialogLaunchAnimator;
}
/** Show the device monitoring dialog. */
public void showDeviceMonitoringDialog(Context quickSettingsContext,
@Nullable Expandable expandable) {
createDialog(quickSettingsContext, expandable);
}
/**
* Return the {@link SecurityButtonConfig} of the security button, or {@code null} if no
* security button should be shown.
*/
@Nullable
public SecurityButtonConfig getButtonConfig(SecurityModel securityModel) {
final boolean isDeviceManaged = securityModel.isDeviceManaged();
final UserInfo currentUser = mUserTracker.getUserInfo();
final boolean isDemoDevice = UserManager.isDeviceInDemoMode(mContext) && currentUser != null
&& currentUser.isDemo();
final boolean hasWorkProfile = securityModel.getHasWorkProfile();
final boolean hasCACerts = securityModel.getHasCACertInCurrentUser();
final boolean hasCACertsInWorkProfile = securityModel.getHasCACertInWorkProfile();
final boolean isNetworkLoggingEnabled = securityModel.isNetworkLoggingEnabled();
final String vpnName = securityModel.getPrimaryVpnName();
final String vpnNameWorkProfile = securityModel.getWorkProfileVpnName();
final CharSequence organizationName = securityModel.getDeviceOwnerOrganizationName();
final CharSequence workProfileOrganizationName =
securityModel.getWorkProfileOrganizationName();
final boolean isProfileOwnerOfOrganizationOwnedDevice =
securityModel.isProfileOwnerOfOrganizationOwnedDevice();
final boolean isParentalControlsEnabled = securityModel.isParentalControlsEnabled();
final boolean isWorkProfileOn = securityModel.isWorkProfileOn();
final boolean hasDisclosableWorkProfilePolicy = hasCACertsInWorkProfile
|| vpnNameWorkProfile != null || (hasWorkProfile && isNetworkLoggingEnabled);
// Update visibility of footer
boolean isVisible = (isDeviceManaged && !isDemoDevice)
|| hasCACerts
|| vpnName != null
|| isProfileOwnerOfOrganizationOwnedDevice
|| isParentalControlsEnabled
|| (hasDisclosableWorkProfilePolicy && isWorkProfileOn);
if (!isVisible && !DEBUG_FORCE_VISIBLE) {
return null;
}
// 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.
boolean isClickable = !(isProfileOwnerOfOrganizationOwnedDevice
&& (!hasDisclosableWorkProfilePolicy || !isWorkProfileOn));
String text = getFooterText(isDeviceManaged, hasWorkProfile,
hasCACerts, hasCACertsInWorkProfile, isNetworkLoggingEnabled, vpnName,
vpnNameWorkProfile, organizationName, workProfileOrganizationName,
isProfileOwnerOfOrganizationOwnedDevice, isParentalControlsEnabled,
isWorkProfileOn).toString();
Icon icon;
ContentDescription contentDescription = null;
if (isParentalControlsEnabled && securityModel.getDeviceAdminIcon() != null) {
icon = new Icon.Loaded(securityModel.getDeviceAdminIcon(), contentDescription);
} else if (vpnName != null || vpnNameWorkProfile != null) {
if (securityModel.isVpnBranded()) {
icon = new Icon.Resource(R.drawable.stat_sys_branded_vpn, contentDescription);
} else {
icon = new Icon.Resource(R.drawable.stat_sys_vpn_ic, contentDescription);
}
} else {
icon = new Icon.Resource(R.drawable.ic_info_outline, contentDescription);
}
return new SecurityButtonConfig(icon, text, isClickable);
}
@Nullable
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) {
return getManagedDeviceFooterText(hasCACerts, hasCACertsInWorkProfile,
isNetworkLoggingEnabled, vpnName, vpnNameWorkProfile, organizationName);
}
return getManagedAndPersonalProfileFooterText(hasWorkProfile, hasCACerts,
hasCACertsInWorkProfile, isNetworkLoggingEnabled, vpnName, vpnNameWorkProfile,
workProfileOrganizationName, isProfileOwnerOfOrganizationOwnedDevice,
isWorkProfileOn);
}
private String getManagedDeviceFooterText(
boolean hasCACerts, boolean hasCACertsInWorkProfile, boolean isNetworkLoggingEnabled,
String vpnName, String vpnNameWorkProfile, CharSequence organizationName) {
if (hasCACerts || hasCACertsInWorkProfile || isNetworkLoggingEnabled) {
return getManagedDeviceMonitoringText(organizationName);
}
if (vpnName != null || vpnNameWorkProfile != null) {
return getManagedDeviceVpnText(vpnName, vpnNameWorkProfile, organizationName);
}
return getMangedDeviceGeneralText(organizationName);
}
private String getManagedDeviceMonitoringText(CharSequence organizationName) {
if (organizationName == null) {
return mDpm.getResources().getString(
QS_MSG_MANAGEMENT_MONITORING, mManagementMonitoringStringSupplier);
}
return mDpm.getResources().getString(
QS_MSG_NAMED_MANAGEMENT_MONITORING,
() -> mContext.getString(
R.string.quick_settings_disclosure_named_management_monitoring,
organizationName),
organizationName);
}
private String getManagedDeviceVpnText(
String vpnName, String vpnNameWorkProfile, CharSequence organizationName) {
if (vpnName != null && vpnNameWorkProfile != null) {
if (organizationName == null) {
return mDpm.getResources().getString(
QS_MSG_MANAGEMENT_MULTIPLE_VPNS, mManagementMultipleVpnStringSupplier);
}
return mDpm.getResources().getString(
QS_MSG_NAMED_MANAGEMENT_MULTIPLE_VPNS,
() -> mContext.getString(
R.string.quick_settings_disclosure_named_management_vpns,
organizationName),
organizationName);
}
String name = vpnName != null ? vpnName : vpnNameWorkProfile;
if (organizationName == null) {
return mDpm.getResources().getString(
QS_MSG_MANAGEMENT_NAMED_VPN,
() -> mContext.getString(
R.string.quick_settings_disclosure_management_named_vpn,
name),
name);
}
return mDpm.getResources().getString(
QS_MSG_NAMED_MANAGEMENT_NAMED_VPN,
() -> mContext.getString(
R.string.quick_settings_disclosure_named_management_named_vpn,
organizationName,
name),
organizationName,
name);
}
private String getMangedDeviceGeneralText(CharSequence organizationName) {
if (organizationName == null) {
return mDpm.getResources().getString(QS_MSG_MANAGEMENT, mManagementMessageSupplier);
}
if (isFinancedDevice()) {
return mContext.getString(
R.string.quick_settings_financed_disclosure_named_management,
organizationName);
} else {
return mDpm.getResources().getString(
QS_MSG_NAMED_MANAGEMENT,
() -> mContext.getString(
R.string.quick_settings_disclosure_named_management,
organizationName),
organizationName);
}
}
private String getManagedAndPersonalProfileFooterText(boolean hasWorkProfile,
boolean hasCACerts, boolean hasCACertsInWorkProfile, boolean isNetworkLoggingEnabled,
String vpnName, String vpnNameWorkProfile, CharSequence workProfileOrganizationName,
boolean isProfileOwnerOfOrganizationOwnedDevice, boolean isWorkProfileOn) {
if (hasCACerts || (hasCACertsInWorkProfile && isWorkProfileOn)) {
return getMonitoringText(
hasCACerts, hasCACertsInWorkProfile, workProfileOrganizationName,
isWorkProfileOn);
}
if (vpnName != null || (vpnNameWorkProfile != null && isWorkProfileOn)) {
return getVpnText(hasWorkProfile, vpnName, vpnNameWorkProfile, isWorkProfileOn);
}
if (hasWorkProfile && isNetworkLoggingEnabled && isWorkProfileOn) {
return getManagedProfileNetworkActivityText();
}
if (isProfileOwnerOfOrganizationOwnedDevice) {
return getMangedDeviceGeneralText(workProfileOrganizationName);
}
return null;
}
private String getMonitoringText(boolean hasCACerts, boolean hasCACertsInWorkProfile,
CharSequence workProfileOrganizationName, boolean isWorkProfileOn) {
if (hasCACertsInWorkProfile && isWorkProfileOn) {
if (workProfileOrganizationName == null) {
return mDpm.getResources().getString(
QS_MSG_WORK_PROFILE_MONITORING, mWorkProfileMonitoringStringSupplier);
}
return mDpm.getResources().getString(
QS_MSG_NAMED_WORK_PROFILE_MONITORING,
() -> mContext.getString(
R.string.quick_settings_disclosure_named_managed_profile_monitoring,
workProfileOrganizationName),
workProfileOrganizationName);
}
if (hasCACerts) {
return mContext.getString(R.string.quick_settings_disclosure_monitoring);
}
return null;
}
private String getVpnText(boolean hasWorkProfile, String vpnName, String vpnNameWorkProfile,
boolean isWorkProfileOn) {
if (vpnName != null && vpnNameWorkProfile != null) {
return mContext.getString(R.string.quick_settings_disclosure_vpns);
}
if (vpnNameWorkProfile != null && isWorkProfileOn) {
return mDpm.getResources().getString(
QS_MSG_WORK_PROFILE_NAMED_VPN,
() -> mContext.getString(
R.string.quick_settings_disclosure_managed_profile_named_vpn,
vpnNameWorkProfile),
vpnNameWorkProfile);
}
if (vpnName != null) {
if (hasWorkProfile) {
return mDpm.getResources().getString(
QS_MSG_PERSONAL_PROFILE_NAMED_VPN,
() -> mContext.getString(
R.string.quick_settings_disclosure_personal_profile_named_vpn,
vpnName),
vpnName);
}
return mContext.getString(R.string.quick_settings_disclosure_named_vpn,
vpnName);
}
return null;
}
private String getManagedProfileNetworkActivityText() {
return mDpm.getResources().getString(
QS_MSG_WORK_PROFILE_NETWORK, mWorkProfileNetworkStringSupplier);
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == DialogInterface.BUTTON_NEGATIVE) {
final Intent intent = new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS);
dialog.dismiss();
// This dismisses the shade on opening the activity
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
}
}
private void createDialog(Context quickSettingsContext, @Nullable Expandable expandable) {
mShouldUseSettingsButton.set(false);
mBgHandler.post(() -> {
String settingsButtonText = getSettingsButton();
final View dialogView = createDialogView(quickSettingsContext);
mMainHandler.post(() -> {
mDialog = new SystemUIDialog(quickSettingsContext, 0);
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
mDialog.setButton(DialogInterface.BUTTON_POSITIVE, getPositiveButton(), this);
mDialog.setButton(DialogInterface.BUTTON_NEGATIVE, mShouldUseSettingsButton.get()
? settingsButtonText : getNegativeButton(), this);
mDialog.setView(dialogView);
DialogLaunchAnimator.Controller controller =
expandable != null ? expandable.dialogLaunchController(new DialogCuj(
InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG))
: null;
if (controller != null) {
mDialogLaunchAnimator.show(mDialog, controller);
} else {
mDialog.show();
}
});
});
}
@VisibleForTesting
Dialog getDialog() {
return mDialog;
}
@VisibleForTesting
View createDialogView(Context quickSettingsContext) {
if (mSecurityController.isParentalControlsEnabled()) {
return createParentalControlsDialogView(quickSettingsContext);
}
return createOrganizationDialogView(quickSettingsContext);
}
private View createOrganizationDialogView(Context quickSettingsContext) {
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(quickSettingsContext)
.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);
mShouldUseSettingsButton.set(true);
}
// 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());
TextView caCertsSubtitle = (TextView) dialogView.findViewById(R.id.ca_certs_subtitle);
String caCertsSubtitleMessage = mDpm.getResources().getString(
QS_DIALOG_MONITORING_CA_CERT_SUBTITLE, mMonitoringSubtitleCaCertStringSupplier);
caCertsSubtitle.setText(caCertsSubtitleMessage);
}
// 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);
TextView networkLoggingSubtitle = (TextView) dialogView.findViewById(
R.id.network_logging_subtitle);
String networkLoggingSubtitleMessage = mDpm.getResources().getString(
QS_DIALOG_MONITORING_NETWORK_SUBTITLE,
mMonitoringSubtitleNetworkStringSupplier);
networkLoggingSubtitle.setText(networkLoggingSubtitleMessage);
}
// 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());
TextView vpnSubtitle = (TextView) dialogView.findViewById(R.id.vpn_subtitle);
String vpnSubtitleMessage = mDpm.getResources().getString(
QS_DIALOG_MONITORING_VPN_SUBTITLE, mMonitoringSubtitleVpnStringSupplier);
vpnSubtitle.setText(vpnSubtitleMessage);
}
// 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(Context quickSettingsContext) {
View dialogView = LayoutInflater.from(quickSettingsContext)
.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);
}
}
// This should not be called on the main thread to avoid making an IPC.
@VisibleForTesting
String getSettingsButton() {
return mDpm.getResources().getString(
QS_DIALOG_VIEW_POLICIES, mViewPoliciesButtonStringSupplier);
}
private String getPositiveButton() {
return mContext.getString(R.string.ok);
}
@Nullable
private String getNegativeButton() {
if (mSecurityController.isParentalControlsEnabled()) {
return mContext.getString(R.string.monitoring_button_view_controls);
}
return null;
}
@Nullable
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 mDpm.getResources().getString(
QS_DIALOG_NAMED_MANAGEMENT,
() -> mContext.getString(
R.string.monitoring_description_named_management,
organizationName),
organizationName);
}
}
return mDpm.getResources().getString(QS_DIALOG_MANAGEMENT, mManagementDialogStringSupplier);
}
@Nullable
protected CharSequence getCaCertsMessage(boolean isDeviceManaged, boolean hasCACerts,
boolean hasCACertsInWorkProfile) {
if (!(hasCACerts || hasCACertsInWorkProfile)) return null;
if (isDeviceManaged) {
return mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_CA_CERT, mManagementDialogCaCertStringSupplier);
}
if (hasCACertsInWorkProfile) {
return mDpm.getResources().getString(
QS_DIALOG_WORK_PROFILE_CA_CERT, mWorkProfileDialogCaCertStringSupplier);
}
return mContext.getString(R.string.monitoring_description_ca_certificate);
}
@Nullable
protected CharSequence getNetworkLoggingMessage(boolean isDeviceManaged,
boolean isNetworkLoggingEnabled) {
if (!isNetworkLoggingEnabled) return null;
if (isDeviceManaged) {
return mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_NETWORK, mManagementDialogNetworkStringSupplier);
} else {
return mDpm.getResources().getString(
QS_DIALOG_WORK_PROFILE_NETWORK, mWorkProfileDialogNetworkStringSupplier);
}
}
@Nullable
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) {
String namedVpns = mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN,
() -> mContext.getString(
R.string.monitoring_description_two_named_vpns,
vpnName, vpnNameWorkProfile),
vpnName, vpnNameWorkProfile);
message.append(namedVpns);
} else {
String name = vpnName != null ? vpnName : vpnNameWorkProfile;
String namedVp = mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_NAMED_VPN,
() -> mContext.getString(
R.string.monitoring_description_managed_device_named_vpn, name),
name);
message.append(namedVp);
}
} else {
if (vpnName != null && vpnNameWorkProfile != null) {
String namedVpns = mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_TWO_NAMED_VPN,
() -> mContext.getString(
R.string.monitoring_description_two_named_vpns,
vpnName, vpnNameWorkProfile),
vpnName, vpnNameWorkProfile);
message.append(namedVpns);
} else if (vpnNameWorkProfile != null) {
String namedVpn = mDpm.getResources().getString(
QS_DIALOG_WORK_PROFILE_NAMED_VPN,
() -> mContext.getString(
R.string.monitoring_description_managed_profile_named_vpn,
vpnNameWorkProfile),
vpnNameWorkProfile);
message.append(namedVpn);
} else if (hasWorkProfile) {
String namedVpn = mDpm.getResources().getString(
QS_DIALOG_PERSONAL_PROFILE_NAMED_VPN,
() -> mContext.getString(
R.string.monitoring_description_personal_profile_named_vpn,
vpnName),
vpnName);
message.append(namedVpn);
} 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 mDpm.getResources().getString(
QS_DIALOG_MANAGEMENT_TITLE,
mManagementTitleSupplier);
}
}
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
}
}
// TODO(b/259908270): remove and inline direct call to mSecurityController.isFinancedDevice()
private boolean isFinancedDevice() {
if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER,
DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG,
DevicePolicyManager.ADD_ISFINANCED_FEVICE_DEFAULT)) {
return mSecurityController.isFinancedDevice();
} else {
return mSecurityController.isDeviceManaged()
&& mSecurityController.getDeviceOwnerType(
mSecurityController.getDeviceOwnerComponentOnAnyUser())
== DEVICE_OWNER_TYPE_FINANCED;
}
}
}