Fix up user switch flow a little.
- Remove the long click listeners since the deletion flow wasn't very discoverable or good anyway. Deletion is better accomplished in settings. - The lock screen shows up immediately after user switch and gets called to be shown quite a few times in not very deterministic order. Now, we replace the user grid view with an infinite progress bar while the switch is in progress so it looks more natural. - Switch the background to solid black like in the mocks. Note that this does not fix the case of the lock screen showing up briefly when switching using the notification shade. That will be cleaned up when we replace that view with the UserGridView. Test: Rebooted and verified lock screen still works fine. Bug: 36454400 Change-Id: I19ad8e9305d93a069294e910998749f1f0386b5b
This commit is contained in:
@@ -14,41 +14,58 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fitsSystemWindows="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone">
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:fitsSystemWindows="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="@android:color/black"
|
||||
android:visibility="gone">
|
||||
|
||||
<!-- This progressbar is activated while we're switching users. -->
|
||||
<ProgressBar
|
||||
android:id="@+id/countdown_progress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/car_user_switcher_progress_bar_height"
|
||||
style="@style/CarUserSwitcher.ProgressBar"
|
||||
android:layout_marginTop="@dimen/car_user_switcher_progress_bar_margin_top"
|
||||
android:layout_alignParentTop="true"/>
|
||||
|
||||
<com.android.systemui.statusbar.car.UserGridView
|
||||
android:id="@+id/user_grid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/car_margin"
|
||||
android:layout_marginRight="@dimen/car_margin"
|
||||
android:layout_centerInParent="true" />
|
||||
|
||||
<com.android.systemui.statusbar.car.PageIndicator
|
||||
android:id="@+id/user_switcher_page_indicator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/car_page_indicator_dot_diameter"
|
||||
android:layout_marginTop="@dimen/car_page_indicator_margin_top"
|
||||
android:layout_below="@+id/user_grid" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/start_driving"
|
||||
android:id="@+id/switching_users"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/car_start_driving_height"
|
||||
android:text="@string/start_driving"
|
||||
style="@style/CarUserSwitcher.StartDrivingButton"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true" />
|
||||
</RelativeLayout>
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<RelativeLayout
|
||||
android:id="@+id/container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- This progress bar is the countdown timer. -->
|
||||
<ProgressBar
|
||||
android:id="@+id/countdown_progress"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/car_user_switcher_progress_bar_height"
|
||||
style="@style/CarUserSwitcher.ProgressBar"
|
||||
android:layout_marginTop="@dimen/car_user_switcher_progress_bar_margin_top"
|
||||
android:layout_alignParentTop="true"/>
|
||||
|
||||
<com.android.systemui.statusbar.car.UserGridView
|
||||
android:id="@+id/user_grid"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/car_margin"
|
||||
android:layout_marginRight="@dimen/car_margin"
|
||||
android:layout_centerInParent="true" />
|
||||
|
||||
<com.android.systemui.statusbar.car.PageIndicator
|
||||
android:id="@+id/user_switcher_page_indicator"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/car_page_indicator_dot_diameter"
|
||||
android:layout_marginTop="@dimen/car_page_indicator_margin_top"
|
||||
android:layout_below="@+id/user_grid" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/start_driving"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/car_start_driving_height"
|
||||
android:text="@string/start_driving"
|
||||
style="@style/CarUserSwitcher.StartDrivingButton"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerHorizontal="true" />
|
||||
</RelativeLayout>
|
||||
</FrameLayout>
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package com.android.systemui.statusbar.car;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.content.res.Resources;
|
||||
import android.os.CountDownTimer;
|
||||
import android.view.View;
|
||||
@@ -31,11 +33,16 @@ import com.android.systemui.statusbar.policy.UserSwitcherController;
|
||||
*/
|
||||
public class FullscreenUserSwitcher {
|
||||
private final View mContainer;
|
||||
private final View mParent;
|
||||
private final UserGridView mUserGridView;
|
||||
private final UserSwitcherController mUserSwitcherController;
|
||||
private final ProgressBar mProgressBar;
|
||||
private final ProgressBar mSwitchingUsers;
|
||||
private final int mLoginTimeoutMs;
|
||||
private final int mAnimUpdateIntervalMs;
|
||||
private final int mShortAnimDuration;
|
||||
|
||||
private boolean mShowing;
|
||||
|
||||
private CountDownTimer mTimer;
|
||||
|
||||
@@ -43,9 +50,15 @@ public class FullscreenUserSwitcher {
|
||||
UserSwitcherController userSwitcherController,
|
||||
ViewStub containerStub) {
|
||||
mUserSwitcherController = userSwitcherController;
|
||||
mContainer = containerStub.inflate();
|
||||
mParent = containerStub.inflate();
|
||||
mContainer = mParent.findViewById(R.id.container);
|
||||
mUserGridView = mContainer.findViewById(R.id.user_grid);
|
||||
mUserGridView.init(statusBar, mUserSwitcherController);
|
||||
mUserGridView.setUserSelectionListener(record -> {
|
||||
if (!record.isCurrent) {
|
||||
toggleSwitchInProgress(true);
|
||||
}
|
||||
});
|
||||
|
||||
PageIndicator pageIndicator = mContainer.findViewById(R.id.user_switcher_page_indicator);
|
||||
pageIndicator.setupWithViewPager(mUserGridView);
|
||||
@@ -54,20 +67,64 @@ public class FullscreenUserSwitcher {
|
||||
Resources res = mContainer.getResources();
|
||||
mLoginTimeoutMs = res.getInteger(R.integer.car_user_switcher_timeout_ms);
|
||||
mAnimUpdateIntervalMs = res.getInteger(R.integer.car_user_switcher_anim_update_ms);
|
||||
mShortAnimDuration = res.getInteger(android.R.integer.config_shortAnimTime);
|
||||
|
||||
mContainer.findViewById(R.id.start_driving).setOnClickListener(v -> {
|
||||
cancelTimer();
|
||||
automaticallySelectUser();
|
||||
});
|
||||
|
||||
mSwitchingUsers = mParent.findViewById(R.id.switching_users);
|
||||
}
|
||||
|
||||
public void onUserSwitched(int newUserId) {
|
||||
mUserGridView.onUserSwitched(newUserId);
|
||||
}
|
||||
|
||||
private void toggleSwitchInProgress(boolean inProgress) {
|
||||
if (inProgress) {
|
||||
crossFade(mSwitchingUsers, mContainer);
|
||||
} else {
|
||||
crossFade(mContainer, mSwitchingUsers);
|
||||
}
|
||||
}
|
||||
|
||||
private void crossFade(View incoming, View outgoing) {
|
||||
incoming.animate()
|
||||
.alpha(1.0f)
|
||||
.setDuration(mShortAnimDuration)
|
||||
.setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animator) {
|
||||
incoming.setAlpha(0.0f);
|
||||
incoming.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
|
||||
outgoing.animate()
|
||||
.alpha(0.0f)
|
||||
.setDuration(mShortAnimDuration)
|
||||
.setListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
outgoing.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void show() {
|
||||
mContainer.setVisibility(View.VISIBLE);
|
||||
if (mShowing) {
|
||||
return;
|
||||
}
|
||||
mShowing = true;
|
||||
mParent.setVisibility(View.VISIBLE);
|
||||
cancelTimer();
|
||||
|
||||
// This would be the case if we were in the middle of a switch.
|
||||
if (mProgressBar.getVisibility() != View.VISIBLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
mTimer = new CountDownTimer(mLoginTimeoutMs, mAnimUpdateIntervalMs) {
|
||||
@Override
|
||||
public void onTick(long msUntilFinished) {
|
||||
@@ -85,8 +142,10 @@ public class FullscreenUserSwitcher {
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
mShowing = false;
|
||||
cancelTimer();
|
||||
mContainer.setVisibility(View.GONE);
|
||||
toggleSwitchInProgress(false);
|
||||
mParent.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void cancelTimer() {
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
package com.android.systemui.statusbar.car;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.UserHandle;
|
||||
import android.support.v4.view.PagerAdapter;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -30,6 +31,7 @@ import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.android.internal.util.UserIcons;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.UserUtil;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
@@ -43,7 +45,7 @@ public class UserGridView extends ViewPager {
|
||||
private StatusBar mStatusBar;
|
||||
private UserSwitcherController mUserSwitcherController;
|
||||
private Adapter mAdapter;
|
||||
private int mPendingUserId = UserHandle.USER_NULL;
|
||||
private UserSelectionListener mUserSelectionListener;
|
||||
|
||||
public UserGridView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
@@ -58,16 +60,12 @@ public class UserGridView extends ViewPager {
|
||||
}
|
||||
|
||||
public void onUserSwitched(int newUserId) {
|
||||
if (mPendingUserId == newUserId) {
|
||||
// Bring up security view after user switch is completed.
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showOfflineAuthUi();
|
||||
}
|
||||
});
|
||||
}
|
||||
mPendingUserId = UserHandle.USER_NULL;
|
||||
// Bring up security view after user switch is completed.
|
||||
post(this::showOfflineAuthUi);
|
||||
}
|
||||
|
||||
public void setUserSelectionListener(UserSelectionListener userSelectionListener) {
|
||||
mUserSelectionListener = userSelectionListener;
|
||||
}
|
||||
|
||||
void showOfflineAuthUi() {
|
||||
@@ -136,15 +134,19 @@ public class UserGridView extends ViewPager {
|
||||
for (int i = position * iconsPerPage; i < limit; i++) {
|
||||
pods.addView(makeUserPod(inflater, context, i, pods));
|
||||
}
|
||||
|
||||
// Dynamic parameters since we specify the weightsum dynamically.
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT, limit);
|
||||
container.addView(pods, params);
|
||||
container.addView(pods);
|
||||
return pods;
|
||||
}
|
||||
|
||||
private Drawable getUserIcon(Context context, UserSwitcherController.UserRecord record) {
|
||||
if (record.isAddUser) {
|
||||
Drawable icon = context.getDrawable(R.drawable.ic_add_circle_qs);
|
||||
icon.setTint(Color.WHITE);
|
||||
return icon;
|
||||
}
|
||||
return UserIcons.getDefaultUserIcon(record.resolveId(), /* light= */ true);
|
||||
}
|
||||
|
||||
private View makeUserPod(LayoutInflater inflater, Context context,
|
||||
int position, ViewGroup parent) {
|
||||
final UserSwitcherController.UserRecord record = mUserAdapter.getItem(position);
|
||||
@@ -160,45 +162,27 @@ public class UserGridView extends ViewPager {
|
||||
|
||||
ImageView iconView = (ImageView) view.findViewById(R.id.user_avatar);
|
||||
if (record == null || record.picture == null) {
|
||||
iconView.setImageDrawable(mUserAdapter.getDrawable(context, record));
|
||||
iconView.setImageDrawable(getUserIcon(context, record));
|
||||
} else {
|
||||
iconView.setImageBitmap(record.picture);
|
||||
}
|
||||
|
||||
iconView.setOnClickListener(v -> {
|
||||
mPendingUserId = UserHandle.USER_NULL;
|
||||
if (record == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (record.isGuest || record.isAddUser) {
|
||||
mUserSwitcherController.switchTo(record);
|
||||
return;
|
||||
if (mUserSelectionListener != null) {
|
||||
mUserSelectionListener.onUserSelected(record);
|
||||
}
|
||||
|
||||
if (record.isCurrent) {
|
||||
showOfflineAuthUi();
|
||||
} else {
|
||||
mPendingUserId = record.info.id;
|
||||
mUserSwitcherController.switchTo(record);
|
||||
}
|
||||
});
|
||||
|
||||
iconView.setOnLongClickListener(v -> {
|
||||
if (record == null || record.isAddUser) {
|
||||
return false;
|
||||
}
|
||||
if (record.isGuest) {
|
||||
if (record.isCurrent) {
|
||||
mUserSwitcherController.switchTo(record);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
UserUtil.deleteUserWithPrompt(getContext(), record.info.id,
|
||||
mUserSwitcherController);
|
||||
return true;
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -247,4 +231,8 @@ public class UserGridView extends ViewPager {
|
||||
mContainer.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
interface UserSelectionListener {
|
||||
void onUserSelected(UserSwitcherController.UserRecord record);
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user