blob: fa523183657a4274e7b341ddfbb41887688a30b8 [file] [log] [blame]
// Copyright 2015 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.keyboard_accessory;
import static org.chromium.ui.base.LocalizationUtils.isLayoutRtl;
import android.content.Context;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
import android.widget.LinearLayout;
import org.chromium.base.ApiCompatibilityUtils;
import org.chromium.chrome.R;
/**
* The Accessory sitting above the keyboard and below the content area. It is used for autofill
* suggestions and manual entry points assisting the user in filling forms.
*/
class KeyboardAccessoryView extends LinearLayout {
private RecyclerView mActionsView;
private TabLayout mTabLayout;
private TabLayout.TabLayoutOnPageChangeListener mPageChangeListener;
private static class HorizontalDividerItemDecoration extends RecyclerView.ItemDecoration {
private final int mHorizontalMargin;
HorizontalDividerItemDecoration(int horizontalMargin) {
this.mHorizontalMargin = horizontalMargin;
}
@Override
public void getItemOffsets(
Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
outRect.right = mHorizontalMargin;
}
}
/**
* Constructor for inflating from XML.
*/
public KeyboardAccessoryView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
mActionsView = findViewById(R.id.actions_view);
initializeHorizontalRecyclerView(mActionsView);
mTabLayout = findViewById(R.id.tabs);
// Apply RTL layout changes to the views children:
ApiCompatibilityUtils.setLayoutDirection(mActionsView,
isLayoutRtl() ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
}
void setVisible(boolean visible) {
if (visible) {
show();
} else {
hide();
}
}
public void setBottomOffset(int bottomOffset) {
MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();
params.setMargins(params.leftMargin, params.topMargin, params.rightMargin, bottomOffset);
setLayoutParams(params);
}
void setActionsAdapter(RecyclerView.Adapter adapter) {
mActionsView.setAdapter(adapter);
}
/**
* Creates a new tab and appends it to the end of the tab layout at the start of the bar.
* @param icon The icon to be displayed in the tab bar.
* @param contentDescription The contentDescription to be used for the tab icon.
*/
void addTabAt(int position, Drawable icon, CharSequence contentDescription) {
if (mTabLayout == null) return; // Inflation not done yet. Will be invoked again afterwards.
TabLayout.Tab tab = mTabLayout.newTab();
tab.setIcon(icon.mutate()); // mutate() needed to change the active tint.
tab.setContentDescription(contentDescription);
mTabLayout.addTab(tab, position, false);
}
void removeTabAt(int position) {
if (mTabLayout == null) return; // Inflation not done yet. Will be invoked again afterwards.
TabLayout.Tab tab = mTabLayout.getTabAt(position);
if (tab == null) return; // The tab was already removed.
mTabLayout.removeTab(tab);
}
/**
* Removes all tabs.
*/
void clearTabs() {
if (mTabLayout == null) return; // Inflation not done yet. Will be invoked again afterwards.
mTabLayout.removeAllTabs();
}
ViewPager.OnPageChangeListener getPageChangeListener() {
if (mPageChangeListener == null) {
mPageChangeListener = new TabLayout.TabLayoutOnPageChangeListener(mTabLayout);
}
return mPageChangeListener;
}
void setTabSelectionAdapter(TabLayout.OnTabSelectedListener tabSelectionCallbacks) {
mTabLayout.clearOnTabSelectedListeners();
mTabLayout.addOnTabSelectedListener(tabSelectionCallbacks);
}
void setActiveTabColor(Integer activeTab) {
for (int i = mTabLayout.getTabCount() - 1; i >= 0; i--) {
TabLayout.Tab t = mTabLayout.getTabAt(i);
if (t == null || t.getIcon() == null) continue;
if (activeTab == null || i != activeTab) {
t.getIcon().clearColorFilter();
} else {
t.getIcon().setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_ATOP);
}
}
}
private void show() {
bringToFront(); // Needs to overlay every component and the bottom sheet - like a keyboard.
setVisibility(View.VISIBLE);
announceForAccessibility(((ViewGroup) getParent()).getContentDescription());
}
private void hide() {
setVisibility(View.GONE);
}
private void initializeHorizontalRecyclerView(RecyclerView recyclerView) {
// Set horizontal layout.
recyclerView.setLayoutManager(
new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
int pad = getResources().getDimensionPixelSize(R.dimen.keyboard_accessory_padding);
// Create margins between every element.
recyclerView.addItemDecoration(new HorizontalDividerItemDecoration(pad));
// Remove all animations - the accessory shouldn't be visibly built anyway.
recyclerView.setItemAnimator(null);
recyclerView.setPadding(isLayoutRtl() ? 0 : pad, 0, isLayoutRtl() ? pad : 0, 0);
}
}