1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera;
18
19import android.app.Activity;
20import android.content.Context;
21import android.graphics.PixelFormat;
22import android.os.Handler;
23import android.view.LayoutInflater;
24import android.view.View;
25import android.view.WindowManager;
26import android.widget.TextView;
27
28import com.android.camera.debug.Log;
29import com.android.camera.util.AndroidServices;
30import com.android.camera2.R;
31
32/**
33 * A on-screen hint is a view containing a little message for the user and will
34 * be shown on the screen continuously.  This class helps you create and show
35 * those.
36 *
37 * <p>
38 * When the view is shown to the user, appears as a floating view over the
39 * application.
40 * <p>
41 * The easiest way to use this class is to call one of the static methods that
42 * constructs everything you need and returns a new {@code OnScreenHint} object.
43 */
44public class OnScreenHint {
45    static final Log.Tag TAG = new Log.Tag("OnScreenHint");
46
47    View mView;
48    View mNextView;
49
50    private final WindowManager.LayoutParams mParams =
51            new WindowManager.LayoutParams();
52    private final WindowManager mWM;
53    private final Handler mHandler = new Handler();
54
55    /**
56     * Construct an empty OnScreenHint object.
57     *
58     * @param activity An activity from which to create a {@link WindowManager}
59     *        to create and attach a view. This must be an Activity, not an
60     *        application context, otherwise app will crash upon display of the
61     *        hint due to adding a view to a application {@link WindowManager}
62     *        that doesn't allow view attachment.
63     */
64    private OnScreenHint(Activity activity) {
65        mWM = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
66
67        mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
68        mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
69        mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
70                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
71        mParams.format = PixelFormat.TRANSLUCENT;
72        mParams.windowAnimations = R.style.Animation_OnScreenHint;
73        mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
74        mParams.setTitle("OnScreenHint");
75    }
76
77    /**
78     * Show the view on the screen.
79     */
80    public void show() {
81        if (mNextView == null) {
82            throw new RuntimeException("View is not initialized");
83        }
84        mHandler.post(mShow);
85    }
86
87    /**
88     * Close the view if it's showing.
89     */
90    public void cancel() {
91        mHandler.post(mHide);
92    }
93
94    /**
95     * Make a standard hint that just contains a text view.
96     *
97     * @param activity An activity from which to create a {@link WindowManager}
98     *        to create and attach a view. This must be an Activity, not an
99     *        application context, otherwise app will crash upon display of the
100     *        hint due to adding a view to a application {@link WindowManager}
101     *        that doesn't allow view attachment.
102     * @param text The text to show.  Can be formatted text.
103     *
104     */
105    public static OnScreenHint makeText(Activity activity, CharSequence text) {
106        OnScreenHint result = new OnScreenHint(activity);
107
108        LayoutInflater inflate = (LayoutInflater) activity.getSystemService(
109                Context.LAYOUT_INFLATER_SERVICE);
110        View v = inflate.inflate(R.layout.on_screen_hint, null);
111        TextView tv = (TextView) v.findViewById(R.id.message);
112        tv.setText(text);
113
114        result.mNextView = v;
115
116        return result;
117    }
118
119    /**
120     * Update the text in a OnScreenHint that was previously created using one
121     * of the makeText() methods.
122     * @param s The new text for the OnScreenHint.
123     */
124    public void setText(CharSequence s) {
125        if (mNextView == null) {
126            throw new RuntimeException("This OnScreenHint was not "
127                    + "created with OnScreenHint.makeText()");
128        }
129        TextView tv = (TextView) mNextView.findViewById(R.id.message);
130        if (tv == null) {
131            throw new RuntimeException("This OnScreenHint was not "
132                    + "created with OnScreenHint.makeText()");
133        }
134        tv.setText(s);
135    }
136
137    private synchronized void handleShow() {
138        if (mView != mNextView) {
139            // remove the old view if necessary
140            handleHide();
141            mView = mNextView;
142            if (mView.getParent() != null) {
143                mWM.removeView(mView);
144            }
145
146            mWM.addView(mView, mParams);
147        }
148    }
149
150    private synchronized void handleHide() {
151        if (mView != null) {
152            // note: checking parent() just to make sure the view has
153            // been added...  i have seen cases where we get here when
154            // the view isn't yet added, so let's try not to crash.
155            if (mView.getParent() != null) {
156                mWM.removeView(mView);
157            }
158            mView = null;
159        }
160    }
161
162    private final Runnable mShow = new Runnable() {
163        @Override
164        public void run() {
165            handleShow();
166        }
167    };
168
169    private final Runnable mHide = new Runnable() {
170        @Override
171        public void run() {
172            handleHide();
173        }
174    };
175}
176