Merge "Remove unlock dialog from sysui" into rvc-dev

This commit is contained in:
Felipe Leme
2020-04-09 18:53:53 +00:00
committed by Android (Google) Code Review
2 changed files with 7 additions and 392 deletions

View File

@@ -1,268 +0,0 @@
/*
* Copyright (C) 2020 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.car.userswitcher;
import android.app.admin.DevicePolicyManager;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Main;
import javax.inject.Inject;
import javax.inject.Singleton;
/**
* A helper class displays an unlock dialog and receives broadcast about detecting trusted device
* & unlocking state to show the appropriate message on the dialog.
*/
@Singleton
class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{
private static final String TAG = CarTrustAgentUnlockDialogHelper.class.getSimpleName();
private final Context mContext;
private final Resources mResources;
private final WindowManager mWindowManager;
private final UserManager mUserManager;
private final WindowManager.LayoutParams mParams;
/**
* Not using Dialog because context passed from {@link FullscreenUserSwitcherViewMediator}
* is not an activity.
*/
private final View mUnlockDialogLayout;
private final TextView mUnlockingText;
private final Button mButton;
private final IntentFilter mFilter;
private int mUid;
private boolean mIsDialogShowing;
private OnHideListener mOnHideListener;
@Inject
CarTrustAgentUnlockDialogHelper(Context context, @Main Resources resources,
UserManager userManager, WindowManager windowManager) {
mContext = context;
mResources = resources;
mUserManager = userManager;
mWindowManager = windowManager;
mParams = createLayoutParams();
mFilter = getIntentFilter();
mParams.packageName = mContext.getPackageName();
mParams.setTitle(mContext.getString(R.string.unlock_dialog_title));
mUnlockDialogLayout = LayoutInflater.from(mContext).inflate(
R.layout.trust_agent_unlock_dialog, null);
mUnlockDialogLayout.setLayoutParams(mParams);
View dialogParent = mUnlockDialogLayout.findViewById(R.id.unlock_dialog_parent);
dialogParent.setOnTouchListener((v, event)-> {
hideUnlockDialog(/* dismissUserSwitcher= */ false);
return true;
});
View unlockDialog = mUnlockDialogLayout.findViewById(R.id.unlock_dialog);
unlockDialog.setOnTouchListener((v, event) -> {
// If the person taps inside the unlock dialog, the touch event will be intercepted here
// and the dialog will not exit
return true;
});
mUnlockingText = mUnlockDialogLayout.findViewById(R.id.unlocking_text);
mButton = mUnlockDialogLayout.findViewById(R.id.enter_pin_button);
mButton.setOnClickListener(v -> {
hideUnlockDialog(/* dismissUserSwitcher= */true);
// TODO(b/138250105) Stop unlock advertising
});
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter != null
&& bluetoothAdapter.getLeState() == BluetoothAdapter.STATE_BLE_ON) {
mUnlockingText.setText(R.string.unlock_dialog_message_start);
}
}
/**
* This filter is listening on:
* {@link BluetoothAdapter#ACTION_BLE_STATE_CHANGED} for starting unlock advertising;
* {@link Intent#ACTION_USER_UNLOCKED} for IHU unlocked
*/
private IntentFilter getIntentFilter() {
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothAdapter.ACTION_BLE_STATE_CHANGED);
filter.addAction(Intent.ACTION_USER_UNLOCKED);
return filter;
}
/**
* Show dialog for the given user
*/
void showUnlockDialog(int uid, OnHideListener listener) {
showUnlockDialogAfterDelay(uid, 0, listener);
}
/**
* Show dialog for the given user after the certain time of delay has elapsed
*
* @param uid the user to unlock
* @param listener listener that listens to dialog hide
*/
void showUnlockDialogAfterDelay(int uid, OnHideListener listener) {
long delayMillis = mResources.getInteger(R.integer.unlock_dialog_delay_ms);
showUnlockDialogAfterDelay(uid, delayMillis, listener);
}
/**
* Show dialog for the given user after the supplied delay has elapsed
*/
private void showUnlockDialogAfterDelay(int uid, long delayMillis, OnHideListener listener) {
setUid(uid);
mOnHideListener = listener;
if (!mIsDialogShowing) {
logd("Receiver registered");
mContext.registerReceiverAsUser(this, UserHandle.ALL, mFilter,
/* broadcastPermission= */ null,
/* scheduler= */ null);
new Handler().postDelayed(() -> {
if (!mUserManager.isUserUnlocked(uid)) {
logd("Showed unlock dialog for user: " + uid + " after " + delayMillis
+ " delay.");
mWindowManager.addView(mUnlockDialogLayout, mParams);
}
}, delayMillis);
}
mIsDialogShowing = true;
}
private void setUid(int uid) {
mUid = uid;
TextView userName = mUnlockDialogLayout.findViewById(R.id.user_name);
userName.setText(mUserManager.getUserInfo(mUid).name);
ImageView avatar = mUnlockDialogLayout.findViewById(R.id.avatar);
avatar.setImageBitmap(mUserManager.getUserIcon(mUid));
setButtonText();
}
private void hideUnlockDialog(boolean dismissUserSwitcher) {
if (!mIsDialogShowing) {
return;
}
mWindowManager.removeView(mUnlockDialogLayout);
logd("Receiver unregistered");
mContext.unregisterReceiver(this);
if (mOnHideListener != null) {
mOnHideListener.onHide(dismissUserSwitcher);
}
mIsDialogShowing = false;
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) {
return;
}
switch (action) {
case BluetoothAdapter.ACTION_BLE_STATE_CHANGED:
logd("Received ACTION_BLE_STATE_CHANGED");
int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
if (state == BluetoothAdapter.STATE_BLE_ON) {
logd("Received BLE_ON");
mUnlockingText.setText(R.string.unlock_dialog_message_start);
}
break;
case Intent.ACTION_USER_UNLOCKED:
int uid = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
if (uid == mUid) {
logd("IHU unlocked");
hideUnlockDialog(/* notifyOnHideListener= */false);
} else {
Log.e(TAG, "Received ACTION_USER_UNLOCKED for unexpected uid: " + uid);
}
break;
default:
Log.e(TAG, "Encountered unexpected action when attempting to set "
+ "unlock state message: " + action);
}
}
// Set button text based on screen lock type
private void setButtonText() {
LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
int passwordQuality = lockPatternUtils.getActivePasswordQuality(mUid);
switch (passwordQuality) {
// PIN
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
mButton.setText(R.string.unlock_dialog_button_text_pin);
break;
// Pattern
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
mButton.setText(R.string.unlock_dialog_button_text_pattern);
break;
// Password
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
mButton.setText(R.string.unlock_dialog_button_text_password);
break;
default:
Log.e(TAG, "Encountered unexpected screen lock type when attempting to set "
+ "button text:" + passwordQuality);
}
}
private WindowManager.LayoutParams createLayoutParams() {
final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,
PixelFormat.TRANSLUCENT
);
attrs.setFitInsetsTypes(0 /* types */);
return attrs;
}
private void logd(String message) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, message);
}
}
/**
* Listener used to notify when the dialog is hidden
*/
interface OnHideListener {
void onHide(boolean dismissUserSwitcher);
}
}

View File

@@ -16,23 +16,14 @@
package com.android.systemui.car.userswitcher;
import android.car.Car;
import android.car.trust.CarTrustAgentEnrollmentManager;
import android.car.userlib.CarUserManagerHelper;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.os.Handler;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Log;
import com.android.internal.widget.LockPatternUtils;
import com.android.systemui.R;
import com.android.systemui.car.CarServiceProvider;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
@@ -52,9 +43,6 @@ public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator {
private static final String TAG = FullscreenUserSwitcherViewMediator.class.getSimpleName();
private final Context mContext;
private final UserManager mUserManager;
private final CarServiceProvider mCarServiceProvider;
private final CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
private final CarStatusBarKeyguardViewManager mCarStatusBarKeyguardViewManager;
private final Handler mMainHandler;
private final StatusBarStateController mStatusBarStateController;
@@ -62,39 +50,12 @@ public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator {
private final ScreenLifecycle mScreenLifecycle;
private final CarStatusBar mCarStatusBar;
private final boolean mIsUserSwitcherEnabled;
private final CarUserManagerHelper mCarUserManagerHelper;
private CarTrustAgentEnrollmentManager mEnrollmentManager;
private UserGridRecyclerView.UserRecord mSelectedUser;
private final CarTrustAgentUnlockDialogHelper.OnHideListener mOnHideListener =
dismissUserSwitcher -> {
if (dismissUserSwitcher) {
dismissUserSwitcher();
} else {
// Re-draw the parent view, otherwise the unlock dialog will not be removed
// from the screen immediately.
invalidateFullscreenUserSwitcherView();
}
};
private final BroadcastReceiver mUserUnlockReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "user 0 is unlocked, SharedPreference is accessible.");
}
showDialogForInitialUser();
mContext.unregisterReceiver(mUserUnlockReceiver);
}
};
@Inject
public FullscreenUserSwitcherViewMediator(
Context context,
@Main Resources resources,
@Main Handler mainHandler,
UserManager userManager,
CarServiceProvider carServiceProvider,
CarTrustAgentUnlockDialogHelper carTrustAgentUnlockDialogHelper,
CarStatusBarKeyguardViewManager carStatusBarKeyguardViewManager,
CarStatusBar carStatusBar,
StatusBarStateController statusBarStateController,
@@ -105,21 +66,12 @@ public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator {
mIsUserSwitcherEnabled = resources.getBoolean(R.bool.config_enableFullscreenUserSwitcher);
mMainHandler = mainHandler;
mUserManager = userManager;
mCarServiceProvider = carServiceProvider;
mCarServiceProvider.addListener(
car -> mEnrollmentManager = (CarTrustAgentEnrollmentManager) car.getCarManager(
Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE));
mUnlockDialogHelper = carTrustAgentUnlockDialogHelper;
mCarStatusBarKeyguardViewManager = carStatusBarKeyguardViewManager;
mCarStatusBar = carStatusBar;
mStatusBarStateController = statusBarStateController;
mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController;
mScreenLifecycle = screenLifecycle;
mCarUserManagerHelper = new CarUserManagerHelper(mContext);
}
@Override
@@ -127,18 +79,6 @@ public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator {
registerUserSwitcherShowListeners();
registerUserSwitcherHideListeners();
registerHideKeyguardListeners();
if (mUserManager.isUserUnlocked(UserHandle.USER_SYSTEM)) {
// User0 is unlocked, switched to the initial user
showDialogForInitialUser();
} else {
// listen to USER_UNLOCKED
mContext.registerReceiverAsUser(mUserUnlockReceiver,
UserHandle.getUserHandleForUid(UserHandle.USER_SYSTEM),
new IntentFilter(Intent.ACTION_USER_UNLOCKED),
/* broadcastPermission= */ null,
/* scheduler= */ null);
}
}
private void registerUserSwitcherShowListeners() {
@@ -194,26 +134,16 @@ public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator {
}
/**
* Every time user clicks on an item in the switcher, if the clicked user has no trusted
* device, we hide the switcher, either gradually or immediately.
* If the user has trusted device, we show an unlock dialog to notify user the unlock
* state.
* When the unlock dialog is dismissed by user, we hide the unlock dialog and the switcher.
* We dismiss the entire keyguard when we hide the switcher if user clicked on the
* foreground user (user we're already logged in as).
* Every time user clicks on an item in the switcher, we hide the switcher.
*
* We dismiss the entire keyguard if user clicked on the foreground user (user we're already
* logged in as).
*/
private void onUserSelected(UserGridRecyclerView.UserRecord record) {
mSelectedUser = record;
if (record.mInfo != null) {
if (hasScreenLock(record.mInfo.id) && hasTrustedDevice(record.mInfo.id)) {
mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, mOnHideListener);
return;
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "no trusted device enrolled for uid: " + record.mInfo.id);
}
hide();
if (record.mType == UserGridRecyclerView.UserRecord.FOREGROUND_USER) {
mCarStatusBar.dismissKeyguard();
}
dismissUserSwitcher();
}
// We automatically dismiss keyguard unless user switcher is being shown above the keyguard.
@@ -234,53 +164,6 @@ public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator {
}
}
private boolean hasScreenLock(int uid) {
LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
return lockPatternUtils.getCredentialTypeForUser(uid)
!= LockPatternUtils.CREDENTIAL_TYPE_NONE;
}
private boolean hasTrustedDevice(int uid) {
if (mEnrollmentManager == null) { // car service not ready, so it cannot be available.
return false;
}
return !mEnrollmentManager.getEnrolledDeviceInfoForUser(uid).isEmpty();
}
private void dismissUserSwitcher() {
if (mSelectedUser == null) {
Log.e(TAG, "Request to dismiss user switcher, but no user selected");
return;
}
if (mSelectedUser.mType == UserGridRecyclerView.UserRecord.FOREGROUND_USER) {
hide();
mCarStatusBar.dismissKeyguard();
return;
}
hide();
}
private void showDialogForInitialUser() {
int initialUser = mCarUserManagerHelper.getInitialUser();
UserInfo initialUserInfo = mUserManager.getUserInfo(initialUser);
mSelectedUser = new UserGridRecyclerView.UserRecord(initialUserInfo,
UserGridRecyclerView.UserRecord.FOREGROUND_USER);
// If the initial user has screen lock and trusted device, display the unlock dialog on the
// keyguard.
if (hasScreenLock(initialUser) && hasTrustedDevice(initialUser)) {
mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser,
mOnHideListener);
} else {
// If no trusted device, dismiss the keyguard.
dismissUserSwitcher();
}
}
private void invalidateFullscreenUserSwitcherView() {
mFullScreenUserSwitcherViewController.invalidate();
}
private void hide() {
mFullScreenUserSwitcherViewController.stop();
}