1608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount/*
2608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * Copyright (C) 2014 The Android Open Source Project
3608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount *
4608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * Licensed under the Apache License, Version 2.0 (the "License");
5608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * you may not use this file except in compliance with the License.
6608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * You may obtain a copy of the License at
7608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount *
8608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount *      http://www.apache.org/licenses/LICENSE-2.0
9608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount *
10608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * Unless required by applicable law or agreed to in writing, software
11608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * distributed under the License is distributed on an "AS IS" BASIS,
12608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * See the License for the specific language governing permissions and
14608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * limitations under the License.
15608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount */
16608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountpackage android.transition;
17608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
18608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountimport android.animation.Animator;
19608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountimport android.animation.ObjectAnimator;
20608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountimport android.animation.RectEvaluator;
21ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.content.Context;
22608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountimport android.graphics.Rect;
23ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mountimport android.util.AttributeSet;
24608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountimport android.view.View;
25608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountimport android.view.ViewGroup;
26608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
27608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount/**
28608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * ChangeClipBounds captures the {@link android.view.View#getClipBounds()} before and after the
29608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount * scene change and animates those changes during the transition.
30608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount */
31608b87d9e57b71a86374a439bf5c3febd1e142f2George Mountpublic class ChangeClipBounds extends Transition {
32608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
33608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    private static final String TAG = "ChangeTransform";
34608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
35608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    private static final String PROPNAME_CLIP = "android:clipBounds:clip";
36608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    private static final String PROPNAME_BOUNDS = "android:clipBounds:bounds";
37608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
38608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    private static final String[] sTransitionProperties = {
39608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            PROPNAME_CLIP,
40608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    };
41608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
42ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    public ChangeClipBounds() {}
43ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount
44ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    public ChangeClipBounds(Context context, AttributeSet attrs) {
45ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount        super(context, attrs);
46ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount    }
47ecd857be3946283ebb4306e2c03ae70f5c5bb152George Mount
48608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    @Override
49608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    public String[] getTransitionProperties() {
50608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        return sTransitionProperties;
51608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
52608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
53608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    private void captureValues(TransitionValues values) {
54608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        View view = values.view;
55608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        if (view.getVisibility() == View.GONE) {
56608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            return;
57608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        }
58608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
59608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        Rect clip = view.getClipBounds();
60608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        values.values.put(PROPNAME_CLIP, clip);
61608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        if (clip == null) {
62608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            Rect bounds = new Rect(0, 0, view.getWidth(), view.getHeight());
63608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            values.values.put(PROPNAME_BOUNDS, bounds);
64608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        }
65608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
66608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
67608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    @Override
68608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    public void captureStartValues(TransitionValues transitionValues) {
69608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        captureValues(transitionValues);
70608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
71608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
72608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    @Override
73608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    public void captureEndValues(TransitionValues transitionValues) {
74608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        captureValues(transitionValues);
75608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
76608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
77608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    @Override
78608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    public Animator createAnimator(final ViewGroup sceneRoot, TransitionValues startValues,
79608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            TransitionValues endValues) {
80608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        if (startValues == null || endValues == null
81608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount                || !startValues.values.containsKey(PROPNAME_CLIP)
82608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount                || !endValues.values.containsKey(PROPNAME_CLIP)) {
83608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            return null;
84608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        }
85608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        Rect start = (Rect) startValues.values.get(PROPNAME_CLIP);
86608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        Rect end = (Rect) endValues.values.get(PROPNAME_CLIP);
87608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        if (start == null && end == null) {
88608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            return null; // No animation required since there is no clip.
89608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        }
90608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
91608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        if (start == null) {
92608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            start = (Rect) startValues.values.get(PROPNAME_BOUNDS);
93608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        } else if (end == null) {
94608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            end = (Rect) endValues.values.get(PROPNAME_BOUNDS);
95608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        }
96608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        if (start.equals(end)) {
97608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount            return null;
98608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        }
99608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount
100608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        endValues.view.setClipBounds(start);
101608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        RectEvaluator evaluator = new RectEvaluator(new Rect());
102608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount        return ObjectAnimator.ofObject(endValues.view, "clipBounds", evaluator, start, end);
103608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount    }
104608b87d9e57b71a86374a439bf5c3febd1e142f2George Mount}
105