TemplateView.java
/*
* Copyright 2017 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 androidx.slice.widget;
import android.content.Context;
import android.os.Build;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.slice.SliceItem;
import androidx.slice.core.SliceAction;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @hide
*/
@RestrictTo(RestrictTo.Scope.LIBRARY)
@RequiresApi(19)
public class TemplateView extends SliceChildView implements
SliceViewPolicy.PolicyChangeListener {
private SliceView mParent;
private final View mForeground;
private final SliceAdapter mAdapter;
private final RecyclerView mRecyclerView;
private ListContent mListContent;
private ArrayList<SliceContent> mDisplayedItems = new ArrayList<>();
private int mDisplayedItemsHeight = 0;
private int[] mLoc = new int[2];
public TemplateView(Context context) {
super(context);
mRecyclerView = new RecyclerView(getContext());
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
mAdapter = new SliceAdapter(context);
mRecyclerView.setAdapter(mAdapter);
addView(mRecyclerView);
mForeground = new View(getContext());
mForeground.setBackground(SliceViewUtil.getDrawable(getContext(),
android.R.attr.selectableItemBackground));
addView(mForeground);
FrameLayout.LayoutParams lp = (LayoutParams) mForeground.getLayoutParams();
lp.width = LayoutParams.MATCH_PARENT;
lp.height = LayoutParams.MATCH_PARENT;
mForeground.setLayoutParams(lp);
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
mParent = (SliceView) getParent();
mAdapter.setParents(mParent, this);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
if (!mViewPolicy.isScrollable() && mDisplayedItems.size() > 0
&& mDisplayedItemsHeight != height) {
updateDisplayedItems(height);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public void setInsets(int l, int t, int r, int b) {
super.setInsets(l, t, r, b);
mAdapter.setInsets(l, t, r, b);
}
/**
* Called when the foreground view handling touch feedback should be activated.
* @param event the event to handle.
*/
public void onForegroundActivated(MotionEvent event) {
if (mParent != null && !mParent.isSliceViewClickable()) {
// Only show highlight if clickable
mForeground.setPressed(false);
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mForeground.getLocationOnScreen(mLoc);
final int x = (int) (event.getRawX() - mLoc[0]);
final int y = (int) (event.getRawY() - mLoc[1]);
mForeground.getBackground().setHotspot(x, y);
}
int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN) {
mForeground.setPressed(true);
} else if (action == MotionEvent.ACTION_CANCEL
|| action == MotionEvent.ACTION_UP
|| action == MotionEvent.ACTION_MOVE) {
mForeground.setPressed(false);
}
}
@Override
public void setPolicy(SliceViewPolicy policy) {
super.setPolicy(policy);
mAdapter.setPolicy(policy);
policy.setListener(this);
}
@Override
public void setActionLoading(SliceItem item) {
mAdapter.onSliceActionLoading(item, 0 /* header position */);
}
@Override
public void setLoadingActions(Set<SliceItem> loadingActions) {
mAdapter.setLoadingActions(loadingActions);
}
@Override
public Set<SliceItem> getLoadingActions() {
return mAdapter.getLoadingActions();
}
@Override
public void setTint(int tint) {
super.setTint(tint);
updateDisplayedItems(getMeasuredHeight());
}
@Override
public void setSliceActionListener(SliceView.OnSliceActionListener observer) {
mObserver = observer;
if (mAdapter != null) {
mAdapter.setSliceObserver(mObserver);
}
}
@Override
public void setSliceActions(List<SliceAction> actions) {
mAdapter.setSliceActions(actions);
}
@Override
public void setSliceContent(ListContent sliceContent) {
mListContent = sliceContent;
int sliceHeight = mListContent.getHeight(mSliceStyle, mViewPolicy);
updateDisplayedItems(sliceHeight);
}
@Override
public void setStyle(SliceStyle style) {
super.setStyle(style);
mAdapter.setStyle(style);
}
@Override
public void setShowLastUpdated(boolean showLastUpdated) {
super.setShowLastUpdated(showLastUpdated);
mAdapter.setShowLastUpdated(showLastUpdated);
}
@Override
public void setLastUpdated(long lastUpdated) {
super.setLastUpdated(lastUpdated);
mAdapter.setLastUpdated(lastUpdated);
}
@Override
public void setAllowTwoLines(boolean allowTwoLines) {
mAdapter.setAllowTwoLines(allowTwoLines);
}
private void updateDisplayedItems(int height) {
if (mListContent == null || !mListContent.isValid()) {
resetView();
return;
}
mDisplayedItems = mListContent.getRowItems(height, mSliceStyle, mViewPolicy);
mDisplayedItemsHeight = mListContent.getListHeight(mDisplayedItems, mSliceStyle,
mViewPolicy);
mAdapter.setSliceItems(mDisplayedItems, mTintColor, mViewPolicy.getMode());
updateOverscroll();
}
private void updateOverscroll() {
boolean scrollable = mDisplayedItemsHeight > getMeasuredHeight();
mRecyclerView.setOverScrollMode(mViewPolicy.isScrollable() && scrollable
? View.OVER_SCROLL_IF_CONTENT_SCROLLS
: View.OVER_SCROLL_NEVER);
}
@Override
public void resetView() {
mDisplayedItemsHeight = 0;
mDisplayedItems.clear();
mAdapter.setSliceItems(null, -1, getMode());
mListContent = null;
}
@Override
public void onScrollingChanged(boolean newScrolling) {
if (mListContent != null) {
updateDisplayedItems(mListContent.getHeight(mSliceStyle, mViewPolicy));
}
}
@Override
public void onMaxHeightChanged(int newNewHeight) {
if (mListContent != null) {
updateDisplayedItems(mListContent.getHeight(mSliceStyle, mViewPolicy));
}
}
@Override
public void onMaxSmallChanged(int newMaxSmallHeight) {
if (mAdapter != null) {
mAdapter.notifyHeaderChanged();
}
}
@Override
public void onModeChanged(int newMode) {
if (mListContent != null) {
updateDisplayedItems(mListContent.getHeight(mSliceStyle, mViewPolicy));
}
}
}