Create dialog to show detecting Batmobile device & unlocking
Bug: 136049501 Test: Manually on IHU Change-Id: I47b55e3032c814623aa5bf5c5c3ec1899c03e98e
This commit is contained in:
@@ -21,4 +21,8 @@
|
||||
coreApp="true">
|
||||
<!-- This permission is required to monitor car power state. -->
|
||||
<uses-permission android:name="android.car.permission.CAR_POWER" />
|
||||
<!-- This permission is required to get the trusted device list of a user. -->
|
||||
<uses-permission android:name="android.car.permission.CAR_ENROLL_TRUST"/>
|
||||
<!-- This permission is required to get bluetooth broadcast. -->
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2019 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
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/unlock_dialog_background_color"/>
|
||||
<padding
|
||||
android:bottom="@*android:dimen/car_padding_2"
|
||||
android:left="@*android:dimen/car_padding_2"
|
||||
android:right="@*android:dimen/car_padding_2"
|
||||
android:top="@*android:dimen/car_padding_2"/>
|
||||
<corners
|
||||
android:radius="@dimen/unlock_dialog_radius"/>
|
||||
</shape>
|
||||
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2019 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
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="@dimen/unlock_dialog_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/unlock_dialog_background"
|
||||
android:padding="@*android:dimen/car_padding_2">
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<ProgressBar
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="@dimen/unlock_dialog_progress_bar_size"
|
||||
android:layout_height="@dimen/unlock_dialog_progress_bar_size" />
|
||||
<ImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_gravity="center"
|
||||
android:layout_width="@dimen/unlock_dialog_avatar_size"
|
||||
android:layout_height="@dimen/unlock_dialog_avatar_size"
|
||||
android:scaleType="fitCenter"/>
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/user_name"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/unlock_dialog_default_user_name"
|
||||
android:textSize="@*android:dimen/car_body1_size"
|
||||
android:textColor="@android:color/white"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/unlocking_text"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginTop="@*android:dimen/car_padding_1"
|
||||
android:text="@string/unlock_dialog_message_default"
|
||||
android:textSize="@*android:dimen/car_body4_size"
|
||||
android:textColor="@color/unlock_dialog_message_text_default"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/enter_pin_button"
|
||||
android:layout_marginTop="@*android:dimen/car_padding_1"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/unlock_dialog_button_text_pin"
|
||||
style="@style/UnlockDialogButton"/>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
@@ -26,4 +26,9 @@
|
||||
<color name="car_user_switcher_add_user_background_color">@*android:color/car_dark_blue_grey_600</color>
|
||||
<color name="car_user_switcher_add_user_add_sign_color">@*android:color/car_body1_light</color>
|
||||
|
||||
<!-- colors for unlock dialog -->
|
||||
<color name="unlock_dialog_background_color">#ff282a2d</color>
|
||||
<color name="unlock_dialog_message_text_default">@*android:color/car_grey_400</color>
|
||||
<color name="unlock_dialog_enter_pin_text_color">#ff66b5ff</color>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -43,4 +43,10 @@
|
||||
<!-- This must be the negative of car_user_switcher_container_height for the animation. -->
|
||||
<dimen name="car_user_switcher_container_anim_height">-420dp</dimen>
|
||||
|
||||
<!-- dimensions for the unlock dialog -->
|
||||
<dimen name="unlock_dialog_width">500dp</dimen>
|
||||
<dimen name="unlock_dialog_radius">16dp</dimen>
|
||||
<dimen name="unlock_dialog_avatar_size">100dp</dimen>
|
||||
<dimen name="unlock_dialog_progress_bar_size">140dp</dimen>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -31,5 +31,7 @@
|
||||
<!--Percentage of the screen height, from the bottom, that a notification panel being peeked
|
||||
at will result in remaining closed the panel if released-->
|
||||
<integer name="notification_settle_close_percentage">80</integer>
|
||||
<!-- The delay before the unlock dialog pops up -->
|
||||
<integer name="unlock_dialog_delay_ms">3000</integer>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -29,4 +29,19 @@
|
||||
<string name="user_add_user_message_setup">When you add a new user, that person needs to set up their space.</string>
|
||||
<!-- Message to inform user that the newly created user will have permissions to update apps for all other users. [CHAR LIMIT=100] -->
|
||||
<string name="user_add_user_message_update">Any user can update apps for all other users.</string>
|
||||
<!-- Default messages displayed on the unlock dialog before unlock advertising started. [CHAR LIMIT=30]-->
|
||||
<string name="unlock_dialog_message_default">Waiting\u2026</string>
|
||||
<!-- Message to inform user that the IHU is looking for trusted device. [CHAR LIMIT=30] -->
|
||||
<string name="unlock_dialog_message_start">Looking for trusted device\u2026</string>
|
||||
|
||||
<!-- Cancel Button text for user who has PIN as security lock. [CHAR LIMIT=30] -->
|
||||
<string name="unlock_dialog_button_text_pin">Enter PIN instead</string>
|
||||
<!-- Cancel Button text for user who has Pattern as security lock. [CHAR LIMIT=30] -->
|
||||
<string name="unlock_dialog_button_text_pattern">Enter Pattern instead</string>
|
||||
<!-- Cancel Button text for user who has Password as security lock. [CHAR LIMIT=30] -->
|
||||
<string name="unlock_dialog_button_text_password">Enter Password instead</string>
|
||||
<!-- Default user name shows on unlock dialog -->
|
||||
<string name="unlock_dialog_default_user_name">Default Name</string>
|
||||
<!-- Default title for unlock dialog -->
|
||||
<string name="unlock_dialog_title">Unlock Dialogue</string>
|
||||
</resources>
|
||||
|
||||
@@ -46,4 +46,12 @@
|
||||
<item name="android:layout_width">96dp</item>
|
||||
<item name="android:background">@drawable/nav_button_background</item>
|
||||
</style>
|
||||
|
||||
<style name="UnlockDialogButton">
|
||||
<item name="android:background">?android:attr/selectableItemBackground</item>
|
||||
<item name="android:textAlignment">center</item>
|
||||
<item name="android:textColor">@color/unlock_dialog_enter_pin_text_color</item>
|
||||
<item name="android:paddingHorizontal">16dp</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -26,6 +26,7 @@ import android.car.Car;
|
||||
import android.car.drivingstate.CarDrivingStateEvent;
|
||||
import android.car.drivingstate.CarUxRestrictionsManager;
|
||||
import android.car.hardware.power.CarPowerManager.CarPowerStateListener;
|
||||
import android.car.trust.CarTrustAgentEnrollmentManager;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.PixelFormat;
|
||||
@@ -957,8 +958,12 @@ public class CarStatusBar extends StatusBar implements
|
||||
UserSwitcherController userSwitcherController =
|
||||
Dependency.get(UserSwitcherController.class);
|
||||
if (userSwitcherController.useFullscreenUserSwitcher()) {
|
||||
Car car = Car.createCar(mContext);
|
||||
CarTrustAgentEnrollmentManager enrollmentManager = (CarTrustAgentEnrollmentManager) car
|
||||
.getCarManager(Car.CAR_TRUST_AGENT_ENROLLMENT_SERVICE);
|
||||
mFullscreenUserSwitcher = new FullscreenUserSwitcher(this,
|
||||
mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub), mContext);
|
||||
mStatusBarWindow.findViewById(R.id.fullscreen_user_switcher_stub),
|
||||
enrollmentManager, mContext);
|
||||
} else {
|
||||
super.createUserSwitcher();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.statusbar.car;
|
||||
|
||||
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.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;
|
||||
|
||||
/**
|
||||
* A helper class displays an unlock dialog and receives broadcast about detecting trusted device
|
||||
* & unlocking state to show the appropriate message on the dialog.
|
||||
*/
|
||||
class CarTrustAgentUnlockDialogHelper extends BroadcastReceiver{
|
||||
private static final String TAG = CarTrustAgentUnlockDialogHelper.class.getSimpleName();
|
||||
|
||||
private final Context mContext;
|
||||
private final WindowManager mWindowManager;
|
||||
private final UserManager mUserManager;
|
||||
private final WindowManager.LayoutParams mParams;
|
||||
/**
|
||||
* Not using Dialog because context passed from {@link FullscreenUserSwitcher} is not an
|
||||
* activity.
|
||||
*/
|
||||
private final View mUnlockDialog;
|
||||
private final TextView mUnlockingText;
|
||||
private final Button mButton;
|
||||
private final IntentFilter mFilter;
|
||||
private int mUid;
|
||||
private boolean mIsDialogShowing;
|
||||
private OnHideListener mOnHideListener;
|
||||
|
||||
CarTrustAgentUnlockDialogHelper(Context context) {
|
||||
mContext = context;
|
||||
mUserManager = mContext.getSystemService(UserManager.class);
|
||||
mWindowManager = mContext.getSystemService(WindowManager.class);
|
||||
mParams = createLayoutParams();
|
||||
mFilter = getIntentFilter();
|
||||
|
||||
mParams.packageName = mContext.getPackageName();
|
||||
mParams.setTitle(mContext.getString(R.string.unlock_dialog_title));
|
||||
|
||||
mUnlockDialog = LayoutInflater.from(mContext).inflate(
|
||||
R.layout.trust_agent_unlock_dialog, null);
|
||||
mUnlockDialog.setLayoutParams(mParams);
|
||||
|
||||
mUnlockingText = mUnlockDialog.findViewById(R.id.unlocking_text);
|
||||
mButton = mUnlockDialog.findViewById(R.id.enter_pin_button);
|
||||
mButton.setOnClickListener(v -> {
|
||||
hideUnlockDialog(/* notifyOnHideListener= */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 = mContext.getResources().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(mUnlockDialog, mParams);
|
||||
}
|
||||
}, delayMillis);
|
||||
}
|
||||
mIsDialogShowing = true;
|
||||
}
|
||||
|
||||
private void setUid(int uid) {
|
||||
mUid = uid;
|
||||
TextView userName = mUnlockDialog.findViewById(R.id.user_name);
|
||||
userName.setText(mUserManager.getUserInfo(mUid).name);
|
||||
ImageView avatar = mUnlockDialog.findViewById(R.id.avatar);
|
||||
avatar.setImageBitmap(mUserManager.getUserIcon(mUid));
|
||||
setButtonText();
|
||||
}
|
||||
|
||||
private void hideUnlockDialog(boolean notifyOnHideListener) {
|
||||
if (!mIsDialogShowing) {
|
||||
return;
|
||||
}
|
||||
mWindowManager.removeView(mUnlockDialog);
|
||||
logd("Receiver unregistered");
|
||||
mContext.unregisterReceiver(this);
|
||||
if (notifyOnHideListener && mOnHideListener != null) {
|
||||
mOnHideListener.onHide();
|
||||
}
|
||||
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 security lock type
|
||||
private void setButtonText() {
|
||||
LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
|
||||
int passwordQuality = lockPatternUtils.getActivePasswordQuality(mUid);
|
||||
switch (passwordQuality) {
|
||||
// PIN
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
|
||||
// Pattern
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
|
||||
mButton.setText(R.string.unlock_dialog_button_text_pattern);
|
||||
break;
|
||||
// Password
|
||||
case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
|
||||
mButton.setText(R.string.unlock_dialog_button_text_password);
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Encountered unexpected security type when attempting to set "
|
||||
+ "button text:" + passwordQuality);
|
||||
}
|
||||
}
|
||||
|
||||
private WindowManager.LayoutParams createLayoutParams() {
|
||||
return 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
|
||||
);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -18,29 +18,60 @@ package com.android.systemui.statusbar.car;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
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.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewStub;
|
||||
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.car.UserGridRecyclerView.UserRecord;
|
||||
|
||||
/**
|
||||
* Manages the fullscreen user switcher.
|
||||
*/
|
||||
public class FullscreenUserSwitcher {
|
||||
private static final String TAG = FullscreenUserSwitcher.class.getSimpleName();
|
||||
// Because user 0 is headless, user count for single user is 2
|
||||
private static final int NUMBER_OF_BACKGROUND_USERS = 1;
|
||||
private final UserGridRecyclerView mUserGridView;
|
||||
private final View mParent;
|
||||
private final int mShortAnimDuration;
|
||||
private final CarStatusBar mStatusBar;
|
||||
private final Context mContext;
|
||||
private final UserManager mUserManager;
|
||||
private final CarTrustAgentEnrollmentManager mEnrollmentManager;
|
||||
private CarTrustAgentUnlockDialogHelper mUnlockDialogHelper;
|
||||
private UserGridRecyclerView.UserRecord mSelectedUser;
|
||||
private CarUserManagerHelper mCarUserManagerHelper;
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub, Context context) {
|
||||
|
||||
public FullscreenUserSwitcher(CarStatusBar statusBar, ViewStub containerStub,
|
||||
CarTrustAgentEnrollmentManager enrollmentManager, Context context) {
|
||||
mStatusBar = statusBar;
|
||||
mParent = containerStub.inflate();
|
||||
// Hide the user grid by default. It will only be made visible by clicking on a cancel
|
||||
// button in a bouncer.
|
||||
hide();
|
||||
mEnrollmentManager = enrollmentManager;
|
||||
mContext = context;
|
||||
|
||||
View container = mParent.findViewById(R.id.container);
|
||||
|
||||
// Initialize user grid.
|
||||
@@ -50,9 +81,51 @@ public class FullscreenUserSwitcher {
|
||||
mUserGridView.setLayoutManager(layoutManager);
|
||||
mUserGridView.buildAdapter();
|
||||
mUserGridView.setUserSelectionListener(this::onUserSelected);
|
||||
mCarUserManagerHelper = new CarUserManagerHelper(context);
|
||||
mUnlockDialogHelper = new CarTrustAgentUnlockDialogHelper(mContext);
|
||||
mUserManager = mContext.getSystemService(UserManager.class);
|
||||
|
||||
mShortAnimDuration = container.getResources()
|
||||
.getInteger(android.R.integer.config_shortAnimTime);
|
||||
IntentFilter filter = new IntentFilter(Intent.ACTION_USER_UNLOCKED);
|
||||
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),
|
||||
filter,
|
||||
/* broadcastPermission= */ null,
|
||||
/* scheduler */ null);
|
||||
}
|
||||
}
|
||||
|
||||
private void showDialogForInitialUser() {
|
||||
int initialUser = mCarUserManagerHelper.getInitialUser();
|
||||
UserInfo initialUserInfo = mUserManager.getUserInfo(initialUser);
|
||||
mSelectedUser = new UserRecord(initialUserInfo,
|
||||
/* isStartGuestSession= */ false,
|
||||
/* isAddUser= */ false,
|
||||
/* isForeground= */ true);
|
||||
// For single user without trusted device, hide the user switcher.
|
||||
if (!hasMultipleUsers() && !hasTrustedDevice(initialUser)) {
|
||||
dismissUserSwitcher();
|
||||
return;
|
||||
}
|
||||
// Show unlock dialog for initial user
|
||||
if (hasTrustedDevice(initialUser)) {
|
||||
mUnlockDialogHelper.showUnlockDialogAfterDelay(initialUser,
|
||||
() -> dismissUserSwitcher());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if there is only one possible user to login in.
|
||||
* In a Multi-User system there is always one background user (user 0)
|
||||
*/
|
||||
private boolean hasMultipleUsers() {
|
||||
return mUserManager.getUserCount() > NUMBER_OF_BACKGROUND_USERS + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,14 +150,33 @@ public class FullscreenUserSwitcher {
|
||||
}
|
||||
|
||||
/**
|
||||
* Every time user clicks on an item in the switcher, we hide the switcher, either
|
||||
* gradually or immediately.
|
||||
* 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.
|
||||
*
|
||||
* We dismiss the entire keyguard if user clicked on the foreground user (user we're already
|
||||
* logged in as).
|
||||
* 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).
|
||||
*/
|
||||
private void onUserSelected(UserGridRecyclerView.UserRecord record) {
|
||||
if (record.mIsForeground) {
|
||||
mSelectedUser = record;
|
||||
if (hasTrustedDevice(record.mInfo.id)) {
|
||||
mUnlockDialogHelper.showUnlockDialog(record.mInfo.id, () -> dismissUserSwitcher());
|
||||
return;
|
||||
}
|
||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "no trusted device enrolled for uid: " + record.mInfo.id);
|
||||
}
|
||||
dismissUserSwitcher();
|
||||
}
|
||||
|
||||
private void dismissUserSwitcher() {
|
||||
if (mSelectedUser == null) {
|
||||
Log.e(TAG, "Request to dismiss user switcher, but no user selected");
|
||||
return;
|
||||
}
|
||||
if (mSelectedUser.mIsForeground) {
|
||||
hide();
|
||||
mStatusBar.dismissKeyguard();
|
||||
return;
|
||||
@@ -106,4 +198,8 @@ public class FullscreenUserSwitcher {
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private boolean hasTrustedDevice(int uid) {
|
||||
return !mEnrollmentManager.getEnrolledDeviceInfoForUser(uid).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user