Extract QSSecurityFooterUtils out of QSSecurityFooter

This CL extracts QSSecurityFooterUtils out of QSSecurityFooter to make
it usable outside of QSSecurityFooter, which is a ViewController scoped
to the Quick Settings fragment. This will make the utils usable outside
this controller, e.g. in an Interactor/ViewModel not scope to QS.

Bug: 242040009
Test: atest QSSecurityFooterTest
Change-Id: If8289c9f28525f35603d03ed0ba3e646b7c06df8
This commit is contained in:
Jordan Demeulenaere
2022-08-23 14:28:49 +02:00
parent e4eb991ba6
commit d7d2de53a1
3 changed files with 848 additions and 778 deletions

View File

@@ -15,122 +15,59 @@
*/ */
package com.android.systemui.qs; 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 static com.android.systemui.qs.dagger.QSFragmentModule.QS_SECURITY_FOOTER_VIEW; import static com.android.systemui.qs.dagger.QSFragmentModule.QS_SECURITY_FOOTER_VIEW;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyEventLogger; import android.app.admin.DevicePolicyEventLogger;
import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.pm.UserInfo;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.UserHandle; import android.os.UserHandle;
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.util.Log;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener; import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.internal.jank.InteractionJankMonitor;
import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.FrameworkStatsLog;
import com.android.systemui.FontSizeUtils; import com.android.systemui.FontSizeUtils;
import com.android.systemui.R; import com.android.systemui.R;
import com.android.systemui.animation.DialogCuj;
import com.android.systemui.animation.DialogLaunchAnimator;
import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.common.shared.model.Icon; import com.android.systemui.common.shared.model.Icon;
import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.qs.dagger.QSScope; import com.android.systemui.qs.dagger.QSScope;
import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig; import com.android.systemui.qs.footer.domain.model.SecurityButtonConfig;
import com.android.systemui.security.data.model.SecurityModel; 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 com.android.systemui.statusbar.policy.SecurityController;
import com.android.systemui.util.ViewController; import com.android.systemui.util.ViewController;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
/** Helper class for the configuration of the QS security footer button. */ /** ViewController for the footer actions. */
// TODO(b/242040009): Remove this class.
@QSScope @QSScope
public class QSSecurityFooter extends ViewController<View> public class QSSecurityFooter extends ViewController<View>
implements OnClickListener, DialogInterface.OnClickListener, implements OnClickListener, VisibilityChangedDispatcher {
VisibilityChangedDispatcher {
protected static final String TAG = "QSSecurityFooter"; 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 static final String INTERACTION_JANK_TAG = "managed_device_info";
private final TextView mFooterText; private final TextView mFooterText;
private final ImageView mPrimaryFooterIcon; private final ImageView mPrimaryFooterIcon;
private Context mContext; private Context mContext;
private final DevicePolicyManager mDpm;
private final Callback mCallback = new Callback(); private final Callback mCallback = new Callback();
private final SecurityController mSecurityController; private final SecurityController mSecurityController;
private final ActivityStarter mActivityStarter;
private final Handler mMainHandler; private final Handler mMainHandler;
private final UserTracker mUserTracker;
private final DialogLaunchAnimator mDialogLaunchAnimator;
private final BroadcastDispatcher mBroadcastDispatcher; private final BroadcastDispatcher mBroadcastDispatcher;
private final QSSecurityFooterUtils mQSSecurityFooterUtils;
private final AtomicBoolean mShouldUseSettingsButton = new AtomicBoolean(false);
private AlertDialog mDialog;
protected H mHandler; protected H mHandler;
private boolean mIsVisible; private boolean mIsVisible;
@@ -152,82 +89,21 @@ public class QSSecurityFooter extends ViewController<View>
} }
}; };
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 @Inject
QSSecurityFooter(@Named(QS_SECURITY_FOOTER_VIEW) View rootView, QSSecurityFooter(@Named(QS_SECURITY_FOOTER_VIEW) View rootView,
UserTracker userTracker, @Main Handler mainHandler, @Main Handler mainHandler, SecurityController securityController,
ActivityStarter activityStarter, SecurityController securityController, @Background Looper bgLooper, BroadcastDispatcher broadcastDispatcher,
DialogLaunchAnimator dialogLaunchAnimator, @Background Looper bgLooper, QSSecurityFooterUtils qSSecurityFooterUtils) {
BroadcastDispatcher broadcastDispatcher) {
super(rootView); super(rootView);
mFooterText = mView.findViewById(R.id.footer_text); mFooterText = mView.findViewById(R.id.footer_text);
mPrimaryFooterIcon = mView.findViewById(R.id.primary_footer_icon); mPrimaryFooterIcon = mView.findViewById(R.id.primary_footer_icon);
mFooterIcon = new Icon.Resource(R.drawable.ic_info_outline); mFooterIcon = new Icon.Resource(R.drawable.ic_info_outline);
mContext = rootView.getContext(); mContext = rootView.getContext();
mDpm = rootView.getContext().getSystemService(DevicePolicyManager.class);
mMainHandler = mainHandler;
mActivityStarter = activityStarter;
mSecurityController = securityController; mSecurityController = securityController;
mMainHandler = mainHandler;
mHandler = new H(bgLooper); mHandler = new H(bgLooper);
mUserTracker = userTracker;
mDialogLaunchAnimator = dialogLaunchAnimator;
mBroadcastDispatcher = broadcastDispatcher; mBroadcastDispatcher = broadcastDispatcher;
mQSSecurityFooterUtils = qSSecurityFooterUtils;
} }
@Override @Override
@@ -292,16 +168,7 @@ public class QSSecurityFooter extends ViewController<View>
// TODO(b/242040009): Remove this. // TODO(b/242040009): Remove this.
public void showDeviceMonitoringDialog() { public void showDeviceMonitoringDialog() {
showDeviceMonitoringDialog(mContext, mView); mQSSecurityFooterUtils.showDeviceMonitoringDialog(mContext, mView);
}
/**
* Show the device monitoring dialog, and expand it from {@code view} if it's not null.
*
* Important: {@code view} must be associated to the same {@link Context} as the QSFragment.
*/
public void showDeviceMonitoringDialog(Context quickSettingsContext, @Nullable View view) {
createDialog(quickSettingsContext, view);
} }
public void refreshState() { public void refreshState() {
@@ -310,7 +177,7 @@ public class QSSecurityFooter extends ViewController<View>
private void handleRefreshState() { private void handleRefreshState() {
SecurityModel securityModel = SecurityModel.create(mSecurityController); SecurityModel securityModel = SecurityModel.create(mSecurityController);
SecurityButtonConfig buttonConfig = getButtonConfig(securityModel); SecurityButtonConfig buttonConfig = mQSSecurityFooterUtils.getButtonConfig(securityModel);
if (buttonConfig == null) { if (buttonConfig == null) {
mIsVisible = false; mIsVisible = false;
@@ -326,577 +193,6 @@ public class QSSecurityFooter extends ViewController<View>
mMainHandler.post(mUpdateDisplayState); mMainHandler.post(mUpdateDisplayState);
} }
/**
* 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;
if (isParentalControlsEnabled) {
icon = new Icon.Loaded(securityModel.getDeviceAdminIcon());
} else if (vpnName != null || vpnNameWorkProfile != null) {
if (securityModel.isVpnBranded()) {
icon = new Icon.Resource(R.drawable.stat_sys_branded_vpn);
} else {
icon = new Icon.Resource(R.drawable.stat_sys_vpn_ic);
}
} else {
icon = new Icon.Resource(R.drawable.ic_info_outline);
}
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 View view) {
mShouldUseSettingsButton.set(false);
mHandler.post(() -> {
String settingsButtonText = getSettingsButton();
final View dialogView = createDialogView();
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);
if (view != null && view.isAggregatedVisible()) {
mDialogLaunchAnimator.showFromView(mDialog, view, new DialogCuj(
InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG));
} else {
mDialog.show();
}
});
});
}
@VisibleForTesting
Dialog getDialog() {
return mDialog;
}
@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);
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() {
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);
}
}
// 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_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);
}
}
private boolean isFinancedDevice() {
return mSecurityController.isDeviceManaged()
&& mSecurityController.getDeviceOwnerType(
mSecurityController.getDeviceOwnerComponentOnAnyUser())
== DEVICE_OWNER_TYPE_FINANCED;
}
private final Runnable mUpdatePrimaryIcon = new Runnable() { private final Runnable mUpdatePrimaryIcon = new Runnable() {
@Override @Override
public void run() { public void run() {
@@ -914,7 +210,7 @@ public class QSSecurityFooter extends ViewController<View>
if (mFooterTextContent != null) { if (mFooterTextContent != null) {
mFooterText.setText(mFooterTextContent); mFooterText.setText(mFooterTextContent);
} }
mView.setVisibility(mIsVisible || DEBUG_FORCE_VISIBLE ? View.VISIBLE : View.GONE); mView.setVisibility(mIsVisible ? View.VISIBLE : View.GONE);
if (mVisibilityChangedListener != null) { if (mVisibilityChangedListener != null) {
mVisibilityChangedListener.onVisibilityChanged(mView.getVisibility()); mVisibilityChangedListener.onVisibilityChanged(mView.getVisibility());
} }
@@ -961,25 +257,4 @@ public class QSSecurityFooter extends ViewController<View>
} }
} }
} }
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
}
}
} }

View File

@@ -0,0 +1,792 @@
/*
* 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.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.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, UserTracker userTracker, @Main Handler mainHandler,
ActivityStarter activityStarter, SecurityController securityController,
@Background Looper bgLooper, DialogLaunchAnimator dialogLaunchAnimator) {
mContext = context;
mDpm = mContext.getSystemService(DevicePolicyManager.class);
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 View view) {
createDialog(quickSettingsContext, view);
}
/**
* 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;
if (isParentalControlsEnabled) {
icon = new Icon.Loaded(securityModel.getDeviceAdminIcon());
} else if (vpnName != null || vpnNameWorkProfile != null) {
if (securityModel.isVpnBranded()) {
icon = new Icon.Resource(R.drawable.stat_sys_branded_vpn);
} else {
icon = new Icon.Resource(R.drawable.stat_sys_vpn_ic);
}
} else {
icon = new Icon.Resource(R.drawable.ic_info_outline);
}
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 View view) {
mShouldUseSettingsButton.set(false);
mBgHandler.post(() -> {
String settingsButtonText = getSettingsButton();
final View dialogView = createDialogView();
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);
if (view != null && view.isAggregatedVisible()) {
mDialogLaunchAnimator.showFromView(mDialog, view, new DialogCuj(
InteractionJankMonitor.CUJ_SHADE_DIALOG_OPEN, INTERACTION_JANK_TAG));
} else {
mDialog.show();
}
});
});
}
@VisibleForTesting
Dialog getDialog() {
return mDialog;
}
@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);
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() {
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);
}
}
// 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_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);
}
}
private boolean isFinancedDevice() {
return mSecurityController.isDeviceManaged()
&& mSecurityController.getDeviceOwnerType(
mSecurityController.getDeviceOwnerComponentOnAnyUser())
== DEVICE_OWNER_TYPE_FINANCED;
}
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
}
}
}

View File

@@ -100,6 +100,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
private TextView mFooterText; private TextView mFooterText;
private TestableImageView mPrimaryFooterIcon; private TestableImageView mPrimaryFooterIcon;
private QSSecurityFooter mFooter; private QSSecurityFooter mFooter;
private QSSecurityFooterUtils mFooterUtils;
@Mock @Mock
private SecurityController mSecurityController; private SecurityController mSecurityController;
@Mock @Mock
@@ -118,13 +119,15 @@ public class QSSecurityFooterTest extends SysuiTestCase {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mTestableLooper = TestableLooper.get(this); mTestableLooper = TestableLooper.get(this);
Looper looper = mTestableLooper.getLooper(); Looper looper = mTestableLooper.getLooper();
Handler mainHandler = new Handler(looper);
when(mUserTracker.getUserInfo()).thenReturn(mock(UserInfo.class)); when(mUserTracker.getUserInfo()).thenReturn(mock(UserInfo.class));
mRootView = (ViewGroup) new LayoutInflaterBuilder(mContext) mRootView = (ViewGroup) new LayoutInflaterBuilder(mContext)
.replace("ImageView", TestableImageView.class) .replace("ImageView", TestableImageView.class)
.build().inflate(R.layout.quick_settings_security_footer, null, false); .build().inflate(R.layout.quick_settings_security_footer, null, false);
mFooter = new QSSecurityFooter(mRootView, mUserTracker, new Handler(looper), mFooterUtils = new QSSecurityFooterUtils(getContext(), mUserTracker, mainHandler,
mActivityStarter, mSecurityController, mDialogLaunchAnimator, looper, mActivityStarter, mSecurityController, looper, mDialogLaunchAnimator);
mBroadcastDispatcher); mFooter = new QSSecurityFooter(mRootView, mainHandler, mSecurityController, looper,
mBroadcastDispatcher, mFooterUtils);
mFooterText = mRootView.findViewById(R.id.footer_text); mFooterText = mRootView.findViewById(R.id.footer_text);
mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon); mPrimaryFooterIcon = mRootView.findViewById(R.id.primary_footer_icon);
@@ -520,7 +523,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
when(mSecurityController.isDeviceManaged()).thenReturn(true); when(mSecurityController.isDeviceManaged()).thenReturn(true);
assertEquals(mContext.getString(R.string.monitoring_title_device_owned), assertEquals(mContext.getString(R.string.monitoring_title_device_owned),
mFooter.getManagementTitle(MANAGING_ORGANIZATION)); mFooterUtils.getManagementTitle(MANAGING_ORGANIZATION));
} }
@Test @Test
@@ -531,12 +534,12 @@ public class QSSecurityFooterTest extends SysuiTestCase {
assertEquals(mContext.getString(R.string.monitoring_title_financed_device, assertEquals(mContext.getString(R.string.monitoring_title_financed_device,
MANAGING_ORGANIZATION), MANAGING_ORGANIZATION),
mFooter.getManagementTitle(MANAGING_ORGANIZATION)); mFooterUtils.getManagementTitle(MANAGING_ORGANIZATION));
} }
@Test @Test
public void testGetManagementMessage_noManagement() { public void testGetManagementMessage_noManagement() {
assertEquals(null, mFooter.getManagementMessage( assertEquals(null, mFooterUtils.getManagementMessage(
/* isDeviceManaged= */ false, MANAGING_ORGANIZATION)); /* isDeviceManaged= */ false, MANAGING_ORGANIZATION));
} }
@@ -544,10 +547,10 @@ public class QSSecurityFooterTest extends SysuiTestCase {
public void testGetManagementMessage_deviceOwner() { public void testGetManagementMessage_deviceOwner() {
assertEquals(mContext.getString(R.string.monitoring_description_named_management, assertEquals(mContext.getString(R.string.monitoring_description_named_management,
MANAGING_ORGANIZATION), MANAGING_ORGANIZATION),
mFooter.getManagementMessage( mFooterUtils.getManagementMessage(
/* isDeviceManaged= */ true, MANAGING_ORGANIZATION)); /* isDeviceManaged= */ true, MANAGING_ORGANIZATION));
assertEquals(mContext.getString(R.string.monitoring_description_management), assertEquals(mContext.getString(R.string.monitoring_description_management),
mFooter.getManagementMessage( mFooterUtils.getManagementMessage(
/* isDeviceManaged= */ true, /* isDeviceManaged= */ true,
/* organizationName= */ null)); /* organizationName= */ null));
} }
@@ -560,68 +563,68 @@ public class QSSecurityFooterTest extends SysuiTestCase {
assertEquals(mContext.getString(R.string.monitoring_financed_description_named_management, assertEquals(mContext.getString(R.string.monitoring_financed_description_named_management,
MANAGING_ORGANIZATION, MANAGING_ORGANIZATION), MANAGING_ORGANIZATION, MANAGING_ORGANIZATION),
mFooter.getManagementMessage( mFooterUtils.getManagementMessage(
/* isDeviceManaged= */ true, MANAGING_ORGANIZATION)); /* isDeviceManaged= */ true, MANAGING_ORGANIZATION));
} }
@Test @Test
public void testGetCaCertsMessage() { public void testGetCaCertsMessage() {
assertEquals(null, mFooter.getCaCertsMessage(true, false, false)); assertEquals(null, mFooterUtils.getCaCertsMessage(true, false, false));
assertEquals(null, mFooter.getCaCertsMessage(false, false, false)); assertEquals(null, mFooterUtils.getCaCertsMessage(false, false, false));
assertEquals(mContext.getString(R.string.monitoring_description_management_ca_certificate), assertEquals(mContext.getString(R.string.monitoring_description_management_ca_certificate),
mFooter.getCaCertsMessage(true, true, true)); mFooterUtils.getCaCertsMessage(true, true, true));
assertEquals(mContext.getString(R.string.monitoring_description_management_ca_certificate), assertEquals(mContext.getString(R.string.monitoring_description_management_ca_certificate),
mFooter.getCaCertsMessage(true, false, true)); mFooterUtils.getCaCertsMessage(true, false, true));
assertEquals(mContext.getString( assertEquals(mContext.getString(
R.string.monitoring_description_managed_profile_ca_certificate), R.string.monitoring_description_managed_profile_ca_certificate),
mFooter.getCaCertsMessage(false, false, true)); mFooterUtils.getCaCertsMessage(false, false, true));
assertEquals(mContext.getString( assertEquals(mContext.getString(
R.string.monitoring_description_ca_certificate), R.string.monitoring_description_ca_certificate),
mFooter.getCaCertsMessage(false, true, false)); mFooterUtils.getCaCertsMessage(false, true, false));
} }
@Test @Test
public void testGetNetworkLoggingMessage() { public void testGetNetworkLoggingMessage() {
// Test network logging message on a device with a device owner. // Test network logging message on a device with a device owner.
// Network traffic may be monitored on the device. // Network traffic may be monitored on the device.
assertEquals(null, mFooter.getNetworkLoggingMessage(true, false)); assertEquals(null, mFooterUtils.getNetworkLoggingMessage(true, false));
assertEquals(mContext.getString(R.string.monitoring_description_management_network_logging), assertEquals(mContext.getString(R.string.monitoring_description_management_network_logging),
mFooter.getNetworkLoggingMessage(true, true)); mFooterUtils.getNetworkLoggingMessage(true, true));
// Test network logging message on a device with a managed profile owner // Test network logging message on a device with a managed profile owner
// Network traffic may be monitored on the work profile. // Network traffic may be monitored on the work profile.
assertEquals(null, mFooter.getNetworkLoggingMessage(false, false)); assertEquals(null, mFooterUtils.getNetworkLoggingMessage(false, false));
assertEquals( assertEquals(
mContext.getString(R.string.monitoring_description_managed_profile_network_logging), mContext.getString(R.string.monitoring_description_managed_profile_network_logging),
mFooter.getNetworkLoggingMessage(false, true)); mFooterUtils.getNetworkLoggingMessage(false, true));
} }
@Test @Test
public void testGetVpnMessage() { public void testGetVpnMessage() {
assertEquals(null, mFooter.getVpnMessage(true, true, null, null)); assertEquals(null, mFooterUtils.getVpnMessage(true, true, null, null));
assertEquals(addLink(mContext.getString(R.string.monitoring_description_two_named_vpns, assertEquals(addLink(mContext.getString(R.string.monitoring_description_two_named_vpns,
VPN_PACKAGE, VPN_PACKAGE_2)), VPN_PACKAGE, VPN_PACKAGE_2)),
mFooter.getVpnMessage(true, true, VPN_PACKAGE, VPN_PACKAGE_2)); mFooterUtils.getVpnMessage(true, true, VPN_PACKAGE, VPN_PACKAGE_2));
assertEquals(addLink(mContext.getString(R.string.monitoring_description_two_named_vpns, assertEquals(addLink(mContext.getString(R.string.monitoring_description_two_named_vpns,
VPN_PACKAGE, VPN_PACKAGE_2)), VPN_PACKAGE, VPN_PACKAGE_2)),
mFooter.getVpnMessage(false, true, VPN_PACKAGE, VPN_PACKAGE_2)); mFooterUtils.getVpnMessage(false, true, VPN_PACKAGE, VPN_PACKAGE_2));
assertEquals(addLink(mContext.getString(R.string.monitoring_description_named_vpn, assertEquals(addLink(mContext.getString(R.string.monitoring_description_named_vpn,
VPN_PACKAGE)), VPN_PACKAGE)),
mFooter.getVpnMessage(true, false, VPN_PACKAGE, null)); mFooterUtils.getVpnMessage(true, false, VPN_PACKAGE, null));
assertEquals(addLink(mContext.getString(R.string.monitoring_description_named_vpn, assertEquals(addLink(mContext.getString(R.string.monitoring_description_named_vpn,
VPN_PACKAGE)), VPN_PACKAGE)),
mFooter.getVpnMessage(false, false, VPN_PACKAGE, null)); mFooterUtils.getVpnMessage(false, false, VPN_PACKAGE, null));
assertEquals(addLink(mContext.getString(R.string.monitoring_description_named_vpn, assertEquals(addLink(mContext.getString(R.string.monitoring_description_named_vpn,
VPN_PACKAGE_2)), VPN_PACKAGE_2)),
mFooter.getVpnMessage(true, true, null, VPN_PACKAGE_2)); mFooterUtils.getVpnMessage(true, true, null, VPN_PACKAGE_2));
assertEquals(addLink(mContext.getString( assertEquals(addLink(mContext.getString(
R.string.monitoring_description_managed_profile_named_vpn, R.string.monitoring_description_managed_profile_named_vpn,
VPN_PACKAGE_2)), VPN_PACKAGE_2)),
mFooter.getVpnMessage(false, true, null, VPN_PACKAGE_2)); mFooterUtils.getVpnMessage(false, true, null, VPN_PACKAGE_2));
assertEquals(addLink(mContext.getString( assertEquals(addLink(mContext.getString(
R.string.monitoring_description_personal_profile_named_vpn, R.string.monitoring_description_personal_profile_named_vpn,
VPN_PACKAGE)), VPN_PACKAGE)),
mFooter.getVpnMessage(false, true, VPN_PACKAGE, null)); mFooterUtils.getVpnMessage(false, true, VPN_PACKAGE, null));
} }
@Test @Test
@@ -631,19 +634,19 @@ public class QSSecurityFooterTest extends SysuiTestCase {
// Device Management subtitle should be shown when there is Device Management section only // Device Management subtitle should be shown when there is Device Management section only
// Other sections visibility will be set somewhere else so it will not be tested here // Other sections visibility will be set somewhere else so it will not be tested here
mFooter.configSubtitleVisibility(true, false, false, false, view); mFooterUtils.configSubtitleVisibility(true, false, false, false, view);
assertEquals(View.VISIBLE, assertEquals(View.VISIBLE,
view.findViewById(R.id.device_management_subtitle).getVisibility()); view.findViewById(R.id.device_management_subtitle).getVisibility());
// If there are multiple sections, all subtitles should be shown // If there are multiple sections, all subtitles should be shown
mFooter.configSubtitleVisibility(true, true, false, false, view); mFooterUtils.configSubtitleVisibility(true, true, false, false, view);
assertEquals(View.VISIBLE, assertEquals(View.VISIBLE,
view.findViewById(R.id.device_management_subtitle).getVisibility()); view.findViewById(R.id.device_management_subtitle).getVisibility());
assertEquals(View.VISIBLE, assertEquals(View.VISIBLE,
view.findViewById(R.id.ca_certs_subtitle).getVisibility()); view.findViewById(R.id.ca_certs_subtitle).getVisibility());
// If there are multiple sections, all subtitles should be shown // If there are multiple sections, all subtitles should be shown
mFooter.configSubtitleVisibility(true, true, true, true, view); mFooterUtils.configSubtitleVisibility(true, true, true, true, view);
assertEquals(View.VISIBLE, assertEquals(View.VISIBLE,
view.findViewById(R.id.device_management_subtitle).getVisibility()); view.findViewById(R.id.device_management_subtitle).getVisibility());
assertEquals(View.VISIBLE, assertEquals(View.VISIBLE,
@@ -655,7 +658,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
// If there are multiple sections, all subtitles should be shown, event if there is no // If there are multiple sections, all subtitles should be shown, event if there is no
// Device Management section // Device Management section
mFooter.configSubtitleVisibility(false, true, true, true, view); mFooterUtils.configSubtitleVisibility(false, true, true, true, view);
assertEquals(View.VISIBLE, assertEquals(View.VISIBLE,
view.findViewById(R.id.ca_certs_subtitle).getVisibility()); view.findViewById(R.id.ca_certs_subtitle).getVisibility());
assertEquals(View.VISIBLE, assertEquals(View.VISIBLE,
@@ -664,13 +667,13 @@ public class QSSecurityFooterTest extends SysuiTestCase {
view.findViewById(R.id.vpn_subtitle).getVisibility()); view.findViewById(R.id.vpn_subtitle).getVisibility());
// If there is only 1 section, the title should be hidden // If there is only 1 section, the title should be hidden
mFooter.configSubtitleVisibility(false, true, false, false, view); mFooterUtils.configSubtitleVisibility(false, true, false, false, view);
assertEquals(View.GONE, assertEquals(View.GONE,
view.findViewById(R.id.ca_certs_subtitle).getVisibility()); view.findViewById(R.id.ca_certs_subtitle).getVisibility());
mFooter.configSubtitleVisibility(false, false, true, false, view); mFooterUtils.configSubtitleVisibility(false, false, true, false, view);
assertEquals(View.GONE, assertEquals(View.GONE,
view.findViewById(R.id.network_logging_subtitle).getVisibility()); view.findViewById(R.id.network_logging_subtitle).getVisibility());
mFooter.configSubtitleVisibility(false, false, false, true, view); mFooterUtils.configSubtitleVisibility(false, false, false, true, view);
assertEquals(View.GONE, assertEquals(View.GONE,
view.findViewById(R.id.vpn_subtitle).getVisibility()); view.findViewById(R.id.vpn_subtitle).getVisibility());
} }
@@ -722,7 +725,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
when(mSecurityController.isParentalControlsEnabled()).thenReturn(true); when(mSecurityController.isParentalControlsEnabled()).thenReturn(true);
when(mSecurityController.getLabel(any())).thenReturn(PARENTAL_CONTROLS_LABEL); when(mSecurityController.getLabel(any())).thenReturn(PARENTAL_CONTROLS_LABEL);
View view = mFooter.createDialogView(); View view = mFooterUtils.createDialogView();
TextView textView = (TextView) view.findViewById(R.id.parental_controls_title); TextView textView = (TextView) view.findViewById(R.id.parental_controls_title);
assertEquals(PARENTAL_CONTROLS_LABEL, textView.getText()); assertEquals(PARENTAL_CONTROLS_LABEL, textView.getText());
} }
@@ -745,7 +748,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT)) when(mSecurityController.getDeviceOwnerType(DEVICE_OWNER_COMPONENT))
.thenReturn(DEVICE_OWNER_TYPE_FINANCED); .thenReturn(DEVICE_OWNER_TYPE_FINANCED);
View view = mFooter.createDialogView(); View view = mFooterUtils.createDialogView();
TextView managementSubtitle = view.findViewById(R.id.device_management_subtitle); TextView managementSubtitle = view.findViewById(R.id.device_management_subtitle);
assertEquals(View.VISIBLE, managementSubtitle.getVisibility()); assertEquals(View.VISIBLE, managementSubtitle.getVisibility());
@@ -756,7 +759,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
assertEquals(mContext.getString(R.string.monitoring_financed_description_named_management, assertEquals(mContext.getString(R.string.monitoring_financed_description_named_management,
MANAGING_ORGANIZATION, MANAGING_ORGANIZATION), managementMessage.getText()); MANAGING_ORGANIZATION, MANAGING_ORGANIZATION), managementMessage.getText());
assertEquals(mContext.getString(R.string.monitoring_button_view_policies), assertEquals(mContext.getString(R.string.monitoring_button_view_policies),
mFooter.getSettingsButton()); mFooterUtils.getSettingsButton());
} }
@Test @Test
@@ -776,7 +779,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
AlertDialog dialog = dialogCaptor.getValue(); AlertDialog dialog = dialogCaptor.getValue();
dialog.create(); dialog.create();
assertEquals(mFooter.getSettingsButton(), assertEquals(mFooterUtils.getSettingsButton(),
dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getText()); dialog.getButton(DialogInterface.BUTTON_NEGATIVE).getText());
dialog.dismiss(); dialog.dismiss();
@@ -819,8 +822,8 @@ public class QSSecurityFooterTest extends SysuiTestCase {
new Intent(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG)); new Intent(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG));
mTestableLooper.processAllMessages(); mTestableLooper.processAllMessages();
assertTrue(mFooter.getDialog().isShowing()); assertTrue(mFooterUtils.getDialog().isShowing());
mFooter.getDialog().dismiss(); mFooterUtils.getDialog().dismiss();
} }
private CharSequence addLink(CharSequence description) { private CharSequence addLink(CharSequence description) {
@@ -828,7 +831,7 @@ public class QSSecurityFooterTest extends SysuiTestCase {
message.append(description); message.append(description);
message.append(mContext.getString(R.string.monitoring_description_vpn_settings_separator)); message.append(mContext.getString(R.string.monitoring_description_vpn_settings_separator));
message.append(mContext.getString(R.string.monitoring_description_vpn_settings), message.append(mContext.getString(R.string.monitoring_description_vpn_settings),
mFooter.new VpnSpan(), 0); mFooterUtils.new VpnSpan(), 0);
return message; return message;
} }
} }