1e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu/*
2e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * Copyright (C) 2014 The Android Open Source Project
3e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu *
4e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * Licensed under the Apache License, Version 2.0 (the "License");
5e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * you may not use this file except in compliance with the License.
6e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * You may obtain a copy of the License at
7e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu *
8e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu *      http://www.apache.org/licenses/LICENSE-2.0
9e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu *
10e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * Unless required by applicable law or agreed to in writing, software
11e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * distributed under the License is distributed on an "AS IS" BASIS,
12e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * See the License for the specific language governing permissions and
14e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * limitations under the License.
15e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu */
16e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
17e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liupackage com.android.camera.widget;
18e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
19e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liuimport android.content.Context;
20e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liuimport android.graphics.Canvas;
21e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liuimport android.util.AttributeSet;
22e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liuimport android.view.View;
23e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liuimport android.widget.TextView;
24e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
25e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu/**
26e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * This class defines a generic cling that provides on-screen instructions. A convenient
27e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * method is provided here to automatically adjust the position of the cling to
28e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * always be consistent with the reference view. The use of the convenient method
29e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu * is optional.
30e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu */
31e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liupublic class Cling extends TextView {
32e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
33e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    private View mReferenceView = null;
34e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    private final int[] mLocation = new int[2];
35e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    private final OnLayoutChangeListener mLayoutChangeListener =
36e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            new OnLayoutChangeListener() {
37e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                @Override
38e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                public void onLayoutChange(View v, int left, int top, int right, int bottom,
39e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                        int oldLeft, int oldTop, int oldRight, int oldBottom) {
40e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                    mDelayDrawingUntilNextLayout = false;
41e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                    // Reference view has changed layout.
42e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                    adjustPosition();
43e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                }
44e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            };
45e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    private boolean mDelayDrawingUntilNextLayout = false;
46e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
47e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    public Cling(Context context, AttributeSet attrs) {
48e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        super(context, attrs);
49e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    }
50e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
51e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    public Cling(Context context) {
52e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        super(context);
53e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    }
54e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
55e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    /**
56e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     * Layout on top of a reference view.
57e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     */
58e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    public void setReferenceView(View v) {
59e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        if (v == null) {
60e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            if (mReferenceView != null) {
61e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                // Clear up existing listeners
62e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                mReferenceView.removeOnLayoutChangeListener(mLayoutChangeListener);
63e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu                mReferenceView = null;
64e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            }
65e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            return;
66e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        }
67e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        mReferenceView = v;
68e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        mReferenceView.addOnLayoutChangeListener(mLayoutChangeListener);
69e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        if (mReferenceView.getVisibility() == GONE) {
70e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            mDelayDrawingUntilNextLayout = true;
71e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        } else {
72e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            adjustPosition();
73e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        }
74e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    }
75e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
76e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    /**
77e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     * Adjust the translation of the cling to stay on top of the reference view.
78e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu     */
793c56192fac54644a301251aae8d1e33c8d60c3e5Spike Sprague    public void adjustPosition() {
80e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        if (mReferenceView == null) {
81e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            return;
82e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        }
83e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        mReferenceView.getLocationInWindow(mLocation);
84e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        int refCenterX = mLocation[0] + mReferenceView.getWidth() / 2;
85e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        int refTopY = mLocation[1];
86e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        // Align center with the reference view and move on top
87e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        int left = refCenterX - getWidth() / 2;
88e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        int top = refTopY - getHeight();
89e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
90e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        getLocationInWindow(mLocation);
91e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        int currentLeft = mLocation[0] - (int) getTranslationX();
92e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        int currentTop = mLocation[1] - (int) getTranslationY();
93e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
94e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        setTranslationX(left - currentLeft);
95e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        setTranslationY(top - currentTop);
96e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    }
97e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu
98e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    @Override
99e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    public void draw(Canvas canvas) {
100e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        if (mDelayDrawingUntilNextLayout) {
101e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu            return;
102e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        }
103e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu        super.draw(canvas);
104e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu    }
105e7d7b9ef5e09ba464306565c6c62302a4d9bbe5eDoris Liu}
106