blob: 68dff14674202c8fa8fc487719a4fb19f36ddb08 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.autofill_assistant.header;
import android.content.Context;
import android.graphics.Rect;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.chromium.chrome.autofill_assistant.R;
import org.chromium.chrome.browser.autofill_assistant.AutofillAssistantUiController;
import org.chromium.chrome.browser.autofill_assistant.carousel.AssistantChipAdapter;
import org.chromium.chrome.browser.autofill_assistant.header.AssistantHeaderViewBinder.ViewHolder;
import org.chromium.chrome.browser.signin.DisplayableProfileData;
import org.chromium.chrome.browser.signin.ProfileDataCache;
import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
import org.chromium.components.signin.base.CoreAccountInfo;
import org.chromium.components.signin.identitymanager.ConsentLevel;
import org.chromium.components.signin.identitymanager.IdentityManager;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
import java.util.Collections;
/**
* Coordinator for the header of the Autofill Assistant.
*/
public class AssistantHeaderCoordinator implements ProfileDataCache.Observer {
private final ProfileDataCache mProfileCache;
private final ViewGroup mView;
private final ImageView mProfileView;
private final String mSignedInAccountEmail;
private final ViewHolder mViewHolder;
private final RecyclerView mChipsContainer;
public AssistantHeaderCoordinator(Context context, AssistantHeaderModel model) {
// Create the poodle and insert it before the status message. We have to create a view
// bigger than the desired poodle size (24dp) because the actual downstream implementation
// needs extra space for the animation.
mView = (ViewGroup) LayoutInflater.from(context).inflate(
R.layout.autofill_assistant_header, /* root= */ null);
AnimatedPoodle poodle = new AnimatedPoodle(context,
context.getResources().getDimensionPixelSize(
R.dimen.autofill_assistant_poodle_view_size),
context.getResources().getDimensionPixelSize(
R.dimen.autofill_assistant_poodle_size));
addPoodle(mView, poodle.getView());
int imageSize = context.getResources().getDimensionPixelSize(
R.dimen.autofill_assistant_profile_size);
mProfileCache = new ProfileDataCache(context, imageSize);
mProfileView = mView.findViewById(R.id.profile_image);
IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager(
AutofillAssistantUiController.getProfile());
mSignedInAccountEmail = CoreAccountInfo.getEmailFrom(
identityManager.getPrimaryAccountInfo(ConsentLevel.SYNC));
setupProfileImage();
mChipsContainer = new RecyclerView(context);
final int innerChipSpacing = context.getResources().getDimensionPixelSize(
R.dimen.autofill_assistant_actions_spacing);
mChipsContainer.addItemDecoration(new RecyclerView.ItemDecoration() {
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view,
@NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
outRect.top = 0;
outRect.bottom = 0;
if (state.getItemCount() <= 1) {
return;
}
// If old position != NO_POSITION, it means the carousel is being animated and we
// should use that position in our logic.
int position = parent.getChildAdapterPosition(view);
RecyclerView.ViewHolder viewHolder = parent.getChildViewHolder(view);
if (viewHolder != null && viewHolder.getOldPosition() != RecyclerView.NO_POSITION) {
position = viewHolder.getOldPosition();
}
if (position == RecyclerView.NO_POSITION) {
return;
}
outRect.left = position == 0 ? 0 : innerChipSpacing;
outRect.right = 0;
}
});
AssistantChipAdapter chipAdapter = new AssistantChipAdapter();
mChipsContainer.setAdapter(chipAdapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
mChipsContainer.setLayoutManager(layoutManager);
mView.setPadding(mChipsContainer.getPaddingLeft(), mChipsContainer.getPaddingTop(),
context.getResources().getDimensionPixelSize(
R.dimen.autofill_assistant_profile_icon_padding),
mChipsContainer.getPaddingBottom());
ViewGroup topContainer = mView.findViewById(R.id.header_top_container);
topContainer.addView(mChipsContainer);
// Bind view and mediator through the model.
mViewHolder =
new AssistantHeaderViewBinder.ViewHolder(context, mView, poodle, mChipsContainer);
AssistantHeaderViewBinder viewBinder = new AssistantHeaderViewBinder();
PropertyModelChangeProcessor.create(model, mViewHolder, viewBinder);
}
@Override
public void onProfileDataUpdated(String accountEmail) {
if (!mSignedInAccountEmail.equals(accountEmail)) {
return;
}
setProfileImageFor(mSignedInAccountEmail);
}
/** Return the view associated to this coordinator. */
public View getView() {
return mView;
}
/** Returns the view containing the chips. */
public View getCarouselView() {
return mChipsContainer;
}
/**
* Cleanup resources when this goes out of scope.
*/
public void destroy() {
if (mSignedInAccountEmail != null) {
mProfileCache.removeObserver(this);
}
}
private void addPoodle(View root, View poodleView) {
ViewGroup parent = root.findViewById(R.id.poodle_wrapper);
parent.addView(poodleView);
}
// TODO(b/130415092): Use image from AGSA if chrome is not signed in.
private void setupProfileImage() {
if (mSignedInAccountEmail != null) {
mProfileCache.addObserver(this);
mProfileCache.update(Collections.singletonList(mSignedInAccountEmail));
}
}
private void setProfileImageFor(String signedInAccountName) {
DisplayableProfileData profileData =
mProfileCache.getProfileDataOrDefault(signedInAccountName);
mProfileView.setImageDrawable(profileData.getImage());
}
}