14121f22713bbed467a977ec0d867ef53989ff374Dake Gu/*
24121f22713bbed467a977ec0d867ef53989ff374Dake Gu * Copyright (C) 2014 The Android Open Source Project
34121f22713bbed467a977ec0d867ef53989ff374Dake Gu *
44121f22713bbed467a977ec0d867ef53989ff374Dake Gu * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
54121f22713bbed467a977ec0d867ef53989ff374Dake Gu * in compliance with the License. You may obtain a copy of the License at
64121f22713bbed467a977ec0d867ef53989ff374Dake Gu *
74121f22713bbed467a977ec0d867ef53989ff374Dake Gu * http://www.apache.org/licenses/LICENSE-2.0
84121f22713bbed467a977ec0d867ef53989ff374Dake Gu *
94121f22713bbed467a977ec0d867ef53989ff374Dake Gu * Unless required by applicable law or agreed to in writing, software distributed under the License
104121f22713bbed467a977ec0d867ef53989ff374Dake Gu * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
114121f22713bbed467a977ec0d867ef53989ff374Dake Gu * or implied. See the License for the specific language governing permissions and limitations under
124121f22713bbed467a977ec0d867ef53989ff374Dake Gu * the License.
134121f22713bbed467a977ec0d867ef53989ff374Dake Gu */
144121f22713bbed467a977ec0d867ef53989ff374Dake Gupackage android.support.v17.leanback.widget;
154121f22713bbed467a977ec0d867ef53989ff374Dake Gu
16d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Guimport android.os.Handler;
174121f22713bbed467a977ec0d867ef53989ff374Dake Guimport android.support.v4.app.ActivityCompat;
189306f07b1d66f4974a81f781d29739b30124fff0George Mountimport android.support.v4.app.SharedElementCallback;
194121f22713bbed467a977ec0d867ef53989ff374Dake Guimport android.support.v4.view.ViewCompat;
20ceb7ab2ddd6e157cd4ade0f14a382c39428163c4Dake Guimport android.support.v17.leanback.R;
2195400e6d31a1ac09e48cb8944a79b7250484aa4cDake Guimport android.support.v17.leanback.transition.TransitionListener;
2295400e6d31a1ac09e48cb8944a79b7250484aa4cDake Guimport android.support.v17.leanback.transition.TransitionHelper;
234121f22713bbed467a977ec0d867ef53989ff374Dake Guimport android.support.v17.leanback.widget.DetailsOverviewRowPresenter.ViewHolder;
244121f22713bbed467a977ec0d867ef53989ff374Dake Guimport android.app.Activity;
254121f22713bbed467a977ec0d867ef53989ff374Dake Guimport android.text.TextUtils;
264121f22713bbed467a977ec0d867ef53989ff374Dake Guimport android.view.View;
2795400e6d31a1ac09e48cb8944a79b7250484aa4cDake Guimport android.view.ViewGroup;
284121f22713bbed467a977ec0d867ef53989ff374Dake Guimport android.view.View.MeasureSpec;
294121f22713bbed467a977ec0d867ef53989ff374Dake Gu
304121f22713bbed467a977ec0d867ef53989ff374Dake Guimport java.util.List;
314121f22713bbed467a977ec0d867ef53989ff374Dake Gu
329306f07b1d66f4974a81f781d29739b30124fff0George Mountfinal class DetailsOverviewSharedElementHelper extends SharedElementCallback {
334121f22713bbed467a977ec0d867ef53989ff374Dake Gu
344121f22713bbed467a977ec0d867ef53989ff374Dake Gu    private ViewHolder mViewHolder;
354121f22713bbed467a977ec0d867ef53989ff374Dake Gu    private Activity mActivityToRunTransition;
364121f22713bbed467a977ec0d867ef53989ff374Dake Gu    private String mSharedElementName;
374121f22713bbed467a977ec0d867ef53989ff374Dake Gu    private int mRightPanelWidth;
384121f22713bbed467a977ec0d867ef53989ff374Dake Gu    private int mRightPanelHeight;
394121f22713bbed467a977ec0d867ef53989ff374Dake Gu
404121f22713bbed467a977ec0d867ef53989ff374Dake Gu    @Override
419306f07b1d66f4974a81f781d29739b30124fff0George Mount    public void onSharedElementStart(List<String> sharedElementNames,
424121f22713bbed467a977ec0d867ef53989ff374Dake Gu            List<View> sharedElements, List<View> sharedElementSnapshots) {
434121f22713bbed467a977ec0d867ef53989ff374Dake Gu        if (sharedElements.size() < 1) {
444121f22713bbed467a977ec0d867ef53989ff374Dake Gu            return;
454121f22713bbed467a977ec0d867ef53989ff374Dake Gu        }
464121f22713bbed467a977ec0d867ef53989ff374Dake Gu        View overviewView = sharedElements.get(0);
47e7b29b745f6562b43ad79074cf5445a26cd4073cDake Gu        if (mViewHolder == null || mViewHolder.mOverviewFrame != overviewView) {
484121f22713bbed467a977ec0d867ef53989ff374Dake Gu            return;
494121f22713bbed467a977ec0d867ef53989ff374Dake Gu        }
504121f22713bbed467a977ec0d867ef53989ff374Dake Gu        View imageView = mViewHolder.mImageView;
514121f22713bbed467a977ec0d867ef53989ff374Dake Gu        final int width = overviewView.getWidth();
524121f22713bbed467a977ec0d867ef53989ff374Dake Gu        final int height = overviewView.getHeight();
534121f22713bbed467a977ec0d867ef53989ff374Dake Gu        imageView.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
544121f22713bbed467a977ec0d867ef53989ff374Dake Gu                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
554121f22713bbed467a977ec0d867ef53989ff374Dake Gu        imageView.layout(0, 0, width, height);
56b0181a77ce38f75a7d218745a330c5d80daacfb6Dake Gu        final View rightPanel = mViewHolder.mRightPanel;
574121f22713bbed467a977ec0d867ef53989ff374Dake Gu        if (mRightPanelWidth != 0 && mRightPanelHeight != 0) {
584121f22713bbed467a977ec0d867ef53989ff374Dake Gu            rightPanel.measure(MeasureSpec.makeMeasureSpec(mRightPanelWidth, MeasureSpec.EXACTLY),
594121f22713bbed467a977ec0d867ef53989ff374Dake Gu                    MeasureSpec.makeMeasureSpec(mRightPanelHeight, MeasureSpec.EXACTLY));
604121f22713bbed467a977ec0d867ef53989ff374Dake Gu            rightPanel.layout(width, rightPanel.getTop(), width + mRightPanelWidth,
614121f22713bbed467a977ec0d867ef53989ff374Dake Gu                    rightPanel.getTop() + mRightPanelHeight);
624121f22713bbed467a977ec0d867ef53989ff374Dake Gu        } else {
634121f22713bbed467a977ec0d867ef53989ff374Dake Gu            rightPanel.offsetLeftAndRight(width - rightPanel.getLeft());
644121f22713bbed467a977ec0d867ef53989ff374Dake Gu        }
6572a2146f4c3e6dbb84a5f9f92e7ab42d142dab04Dake Gu        mViewHolder.mActionsRow.setVisibility(View.INVISIBLE);
6672a2146f4c3e6dbb84a5f9f92e7ab42d142dab04Dake Gu        mViewHolder.mDetailsDescriptionFrame.setVisibility(View.INVISIBLE);
67b0181a77ce38f75a7d218745a330c5d80daacfb6Dake Gu    }
68b0181a77ce38f75a7d218745a330c5d80daacfb6Dake Gu
69b0181a77ce38f75a7d218745a330c5d80daacfb6Dake Gu    @Override
709306f07b1d66f4974a81f781d29739b30124fff0George Mount    public void onSharedElementEnd(List<String> sharedElementNames,
71b0181a77ce38f75a7d218745a330c5d80daacfb6Dake Gu            List<View> sharedElements, List<View> sharedElementSnapshots) {
72b0181a77ce38f75a7d218745a330c5d80daacfb6Dake Gu        if (sharedElements.size() < 1) {
73b0181a77ce38f75a7d218745a330c5d80daacfb6Dake Gu            return;
74b0181a77ce38f75a7d218745a330c5d80daacfb6Dake Gu        }
75b0181a77ce38f75a7d218745a330c5d80daacfb6Dake Gu        View overviewView = sharedElements.get(0);
76e7b29b745f6562b43ad79074cf5445a26cd4073cDake Gu        if (mViewHolder == null || mViewHolder.mOverviewFrame != overviewView) {
77b0181a77ce38f75a7d218745a330c5d80daacfb6Dake Gu            return;
78b0181a77ce38f75a7d218745a330c5d80daacfb6Dake Gu        }
7995400e6d31a1ac09e48cb8944a79b7250484aa4cDake Gu        // temporary let action row take focus so we defer button background animation
8095400e6d31a1ac09e48cb8944a79b7250484aa4cDake Gu        mViewHolder.mActionsRow.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
8172a2146f4c3e6dbb84a5f9f92e7ab42d142dab04Dake Gu        mViewHolder.mActionsRow.setVisibility(View.VISIBLE);
8295400e6d31a1ac09e48cb8944a79b7250484aa4cDake Gu        mViewHolder.mActionsRow.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
8372a2146f4c3e6dbb84a5f9f92e7ab42d142dab04Dake Gu        mViewHolder.mDetailsDescriptionFrame.setVisibility(View.VISIBLE);
844121f22713bbed467a977ec0d867ef53989ff374Dake Gu    }
854121f22713bbed467a977ec0d867ef53989ff374Dake Gu
86d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu    void setSharedElementEnterTransition(Activity activity, String sharedElementName,
87d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu            long timeoutMs) {
884121f22713bbed467a977ec0d867ef53989ff374Dake Gu        if (activity == null && !TextUtils.isEmpty(sharedElementName) ||
894121f22713bbed467a977ec0d867ef53989ff374Dake Gu                activity != null && TextUtils.isEmpty(sharedElementName)) {
904121f22713bbed467a977ec0d867ef53989ff374Dake Gu            throw new IllegalArgumentException();
914121f22713bbed467a977ec0d867ef53989ff374Dake Gu        }
924121f22713bbed467a977ec0d867ef53989ff374Dake Gu        if (activity == mActivityToRunTransition &&
934121f22713bbed467a977ec0d867ef53989ff374Dake Gu                TextUtils.equals(sharedElementName, mSharedElementName)) {
944121f22713bbed467a977ec0d867ef53989ff374Dake Gu            return;
954121f22713bbed467a977ec0d867ef53989ff374Dake Gu        }
964121f22713bbed467a977ec0d867ef53989ff374Dake Gu        if (mActivityToRunTransition != null) {
979306f07b1d66f4974a81f781d29739b30124fff0George Mount            ActivityCompat.setEnterSharedElementCallback(mActivityToRunTransition, null);
984121f22713bbed467a977ec0d867ef53989ff374Dake Gu        }
994121f22713bbed467a977ec0d867ef53989ff374Dake Gu        mActivityToRunTransition = activity;
1004121f22713bbed467a977ec0d867ef53989ff374Dake Gu        mSharedElementName = sharedElementName;
1014121f22713bbed467a977ec0d867ef53989ff374Dake Gu        if (mActivityToRunTransition != null) {
1029306f07b1d66f4974a81f781d29739b30124fff0George Mount            ActivityCompat.setEnterSharedElementCallback(mActivityToRunTransition, this);
1034121f22713bbed467a977ec0d867ef53989ff374Dake Gu            ActivityCompat.postponeEnterTransition(mActivityToRunTransition);
104d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu            if (timeoutMs > 0) {
105d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                new Handler().postDelayed(new Runnable() {
106ceb7ab2ddd6e157cd4ade0f14a382c39428163c4Dake Gu                    @Override
107d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                    public void run() {
108d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                        if (mActivityToRunTransition == null) {
109d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                            return;
11095400e6d31a1ac09e48cb8944a79b7250484aa4cDake Gu                        }
111d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                        ActivityCompat.startPostponedEnterTransition(mActivityToRunTransition);
112d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                        mActivityToRunTransition = null;
11395400e6d31a1ac09e48cb8944a79b7250484aa4cDake Gu                    }
114d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                }, timeoutMs);
11595400e6d31a1ac09e48cb8944a79b7250484aa4cDake Gu            }
1164121f22713bbed467a977ec0d867ef53989ff374Dake Gu        }
1174121f22713bbed467a977ec0d867ef53989ff374Dake Gu    }
1184121f22713bbed467a977ec0d867ef53989ff374Dake Gu
1194121f22713bbed467a977ec0d867ef53989ff374Dake Gu    void onBindToDrawable(ViewHolder vh) {
1204121f22713bbed467a977ec0d867ef53989ff374Dake Gu        // After we got a image drawable,  we can determine size of right panel.
1214121f22713bbed467a977ec0d867ef53989ff374Dake Gu        // We want right panel to have fixed size so that the right panel don't change size
1224121f22713bbed467a977ec0d867ef53989ff374Dake Gu        // when the overview is layout as a small bounds in transition.
1234121f22713bbed467a977ec0d867ef53989ff374Dake Gu        mViewHolder = vh;
1244121f22713bbed467a977ec0d867ef53989ff374Dake Gu        mViewHolder.mRightPanel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
1254121f22713bbed467a977ec0d867ef53989ff374Dake Gu            @Override
1264121f22713bbed467a977ec0d867ef53989ff374Dake Gu            public void onLayoutChange(View v, int left, int top, int right, int bottom,
1274121f22713bbed467a977ec0d867ef53989ff374Dake Gu                    int oldLeft, int oldTop, int oldRight, int oldBottom) {
1284121f22713bbed467a977ec0d867ef53989ff374Dake Gu                mViewHolder.mRightPanel.removeOnLayoutChangeListener(this);
1294121f22713bbed467a977ec0d867ef53989ff374Dake Gu                mRightPanelWidth = mViewHolder.mRightPanel.getWidth();
1304121f22713bbed467a977ec0d867ef53989ff374Dake Gu                mRightPanelHeight = mViewHolder.mRightPanel.getHeight();
1314121f22713bbed467a977ec0d867ef53989ff374Dake Gu            }
1324121f22713bbed467a977ec0d867ef53989ff374Dake Gu        });
1334121f22713bbed467a977ec0d867ef53989ff374Dake Gu        if (mActivityToRunTransition != null) {
1344121f22713bbed467a977ec0d867ef53989ff374Dake Gu            mViewHolder.mRightPanel.postOnAnimation(new Runnable() {
1354121f22713bbed467a977ec0d867ef53989ff374Dake Gu                @Override
1364121f22713bbed467a977ec0d867ef53989ff374Dake Gu                public void run() {
137f4482e64217e38c0ad8f344da0e90e9e1cf3aa11Dake Gu                    if (mActivityToRunTransition == null) {
138f4482e64217e38c0ad8f344da0e90e9e1cf3aa11Dake Gu                        return;
139f4482e64217e38c0ad8f344da0e90e9e1cf3aa11Dake Gu                    }
140d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                    final TransitionHelper transitionHelper = TransitionHelper.getInstance();
141d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                    Object transition = transitionHelper.getSharedElementEnterTransition(
142d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                            mActivityToRunTransition.getWindow());
143d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                    if (transition != null) {
144d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                        transitionHelper.setTransitionListener(transition, new TransitionListener() {
145d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                            @Override
146d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                            public void onTransitionEnd(Object transition) {
147d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                                // after transition if the action row still focused, transfer
148d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                                // focus to its children
149d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                                if (mViewHolder.mActionsRow.isFocused()) {
150d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                                    mViewHolder.mActionsRow.requestFocus();
151d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                                }
152d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                                transitionHelper.setTransitionListener(transition, null);
153d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                            }
154d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                        });
155d391b19d1bf663ce300b0f4550e6fbaa7e12b0d4Dake Gu                    }
156e7b29b745f6562b43ad79074cf5445a26cd4073cDake Gu                    ViewCompat.setTransitionName(mViewHolder.mOverviewFrame, mSharedElementName);
1574121f22713bbed467a977ec0d867ef53989ff374Dake Gu                    ActivityCompat.startPostponedEnterTransition(mActivityToRunTransition);
1584121f22713bbed467a977ec0d867ef53989ff374Dake Gu                    mActivityToRunTransition = null;
1594121f22713bbed467a977ec0d867ef53989ff374Dake Gu                    mSharedElementName = null;
1604121f22713bbed467a977ec0d867ef53989ff374Dake Gu                }
1614121f22713bbed467a977ec0d867ef53989ff374Dake Gu            });
1624121f22713bbed467a977ec0d867ef53989ff374Dake Gu        }
1634121f22713bbed467a977ec0d867ef53989ff374Dake Gu    }
1644121f22713bbed467a977ec0d867ef53989ff374Dake Gu}
165