/* * Copyright (C) 2022 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; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.UserInfo; import android.os.UserHandle; import com.android.internal.logging.UiEventLogger; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.qs.QSUserSwitcherEvent; import com.android.systemui.settings.UserTracker; import com.android.systemui.statusbar.phone.SystemUIDialog; import com.android.systemui.statusbar.policy.UserSwitcherController; import javax.inject.Inject; import dagger.assisted.Assisted; import dagger.assisted.AssistedFactory; import dagger.assisted.AssistedInject; /** * Manages handling of guest session persistent notification * and actions to reset guest or exit guest session */ public final class GuestResetOrExitSessionReceiver extends BroadcastReceiver { private static final String TAG = GuestResetOrExitSessionReceiver.class.getSimpleName(); /** * Broadcast sent to the system when guest user needs to be reset. * This is only sent to registered receivers, not manifest receivers. * * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_GUEST_RESET = "android.intent.action.GUEST_RESET"; /** * Broadcast sent to the system when guest user needs to exit. * This is only sent to registered receivers, not manifest receivers. * * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_GUEST_EXIT = "android.intent.action.GUEST_EXIT"; public AlertDialog mExitSessionDialog; public AlertDialog mResetSessionDialog; private final UserTracker mUserTracker; private final BroadcastDispatcher mBroadcastDispatcher; private final ResetSessionDialog.Factory mResetSessionDialogFactory; private final ExitSessionDialog.Factory mExitSessionDialogFactory; @Inject public GuestResetOrExitSessionReceiver(UserTracker userTracker, BroadcastDispatcher broadcastDispatcher, ResetSessionDialog.Factory resetSessionDialogFactory, ExitSessionDialog.Factory exitSessionDialogFactory) { mUserTracker = userTracker; mBroadcastDispatcher = broadcastDispatcher; mResetSessionDialogFactory = resetSessionDialogFactory; mExitSessionDialogFactory = exitSessionDialogFactory; } /** * Register this receiver with the {@link BroadcastDispatcher} */ public void register() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(ACTION_GUEST_RESET); intentFilter.addAction(ACTION_GUEST_EXIT); mBroadcastDispatcher.registerReceiver(this, intentFilter, null /* handler */, UserHandle.SYSTEM); } @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); cancelResetDialog(); cancelExitDialog(); UserInfo currentUser = mUserTracker.getUserInfo(); if (!currentUser.isGuest()) { return; } if (ACTION_GUEST_RESET.equals(action)) { mResetSessionDialog = mResetSessionDialogFactory.create(currentUser.id); mResetSessionDialog.show(); } else if (ACTION_GUEST_EXIT.equals(action)) { mExitSessionDialog = mExitSessionDialogFactory.create(currentUser.id, currentUser.isEphemeral()); mExitSessionDialog.show(); } } private void cancelResetDialog() { if (mResetSessionDialog != null && mResetSessionDialog.isShowing()) { mResetSessionDialog.cancel(); mResetSessionDialog = null; } } private void cancelExitDialog() { if (mExitSessionDialog != null && mExitSessionDialog.isShowing()) { mExitSessionDialog.cancel(); mExitSessionDialog = null; } } /** * Dialog shown when asking for confirmation before * reset and restart of guest user. */ public static final class ResetSessionDialog extends SystemUIDialog implements DialogInterface.OnClickListener { private final UserSwitcherController mUserSwitcherController; private final UiEventLogger mUiEventLogger; private final int mUserId; /** Factory class to create guest reset dialog instance */ @AssistedFactory public interface Factory { /** Create a guest reset dialog instance */ ResetSessionDialog create(int userId); } @AssistedInject ResetSessionDialog(Context context, UserSwitcherController userSwitcherController, UiEventLogger uiEventLogger, @Assisted int userId) { super(context); setTitle(com.android.settingslib.R.string.guest_reset_and_restart_dialog_title); setMessage(context.getString( com.android.settingslib.R.string.guest_reset_and_restart_dialog_message)); setButton(DialogInterface.BUTTON_NEUTRAL, context.getString(android.R.string.cancel), this); setButton(DialogInterface.BUTTON_POSITIVE, context.getString( com.android.settingslib.R.string.guest_reset_guest_confirm_button), this); setCanceledOnTouchOutside(false); mUserSwitcherController = userSwitcherController; mUiEventLogger = uiEventLogger; mUserId = userId; } @Override public void onClick(DialogInterface dialog, int which) { if (which == DialogInterface.BUTTON_POSITIVE) { mUiEventLogger.log(QSUserSwitcherEvent.QS_USER_GUEST_REMOVE); mUserSwitcherController.removeGuestUser(mUserId, UserHandle.USER_NULL); } else if (which == DialogInterface.BUTTON_NEUTRAL) { cancel(); } } } /** * Dialog shown when asking for confirmation before * exit of guest user. */ public static final class ExitSessionDialog extends SystemUIDialog implements DialogInterface.OnClickListener { private final UserSwitcherController mUserSwitcherController; private final int mUserId; private boolean mIsEphemeral; /** Factory class to create guest exit dialog instance */ @AssistedFactory public interface Factory { /** Create a guest exit dialog instance */ ExitSessionDialog create(int userId, boolean isEphemeral); } @AssistedInject ExitSessionDialog(Context context, UserSwitcherController userSwitcherController, @Assisted int userId, @Assisted boolean isEphemeral) { super(context); if (isEphemeral) { setTitle(context.getString( com.android.settingslib.R.string.guest_exit_dialog_title)); setMessage(context.getString( com.android.settingslib.R.string.guest_exit_dialog_message)); setButton(DialogInterface.BUTTON_NEUTRAL, context.getString(android.R.string.cancel), this); setButton(DialogInterface.BUTTON_POSITIVE, context.getString( com.android.settingslib.R.string.guest_exit_dialog_button), this); } else { setTitle(context.getString( com.android.settingslib .R.string.guest_exit_dialog_title_non_ephemeral)); setMessage(context.getString( com.android.settingslib .R.string.guest_exit_dialog_message_non_ephemeral)); setButton(DialogInterface.BUTTON_NEUTRAL, context.getString(android.R.string.cancel), this); setButton(DialogInterface.BUTTON_NEGATIVE, context.getString( com.android.settingslib.R.string.guest_exit_clear_data_button), this); setButton(DialogInterface.BUTTON_POSITIVE, context.getString( com.android.settingslib.R.string.guest_exit_save_data_button), this); } setCanceledOnTouchOutside(false); mUserSwitcherController = userSwitcherController; mUserId = userId; mIsEphemeral = isEphemeral; } @Override public void onClick(DialogInterface dialog, int which) { if (mIsEphemeral) { if (which == DialogInterface.BUTTON_POSITIVE) { // Ephemeral guest: exit guest, guest is removed by the system // on exit, since its marked ephemeral mUserSwitcherController.exitGuestUser(mUserId, UserHandle.USER_NULL, false); } else if (which == DialogInterface.BUTTON_NEUTRAL) { // Cancel clicked, do nothing cancel(); } } else { if (which == DialogInterface.BUTTON_POSITIVE) { // Non-ephemeral guest: exit guest, guest is not removed by the system // on exit, since its marked non-ephemeral mUserSwitcherController.exitGuestUser(mUserId, UserHandle.USER_NULL, false); } else if (which == DialogInterface.BUTTON_NEGATIVE) { // Non-ephemeral guest: remove guest and then exit mUserSwitcherController.exitGuestUser(mUserId, UserHandle.USER_NULL, true); } else if (which == DialogInterface.BUTTON_NEUTRAL) { // Cancel clicked, do nothing cancel(); } } } } }