OnScreenHint.java revision bbc560b5216bbb2e3028020e426ce6a6e0e5df08
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.content.Context;
20import android.content.res.Resources;
21import android.graphics.PixelFormat;
22import android.os.Handler;
23import android.view.Gravity;
24import android.view.LayoutInflater;
25import android.view.View;
26import android.view.WindowManager;
27import android.widget.TextView;
28
29/**
30 * A on-screen hint is a view containing a little message for the user and will
31 * be shown on the screen continuously.  This class helps you create and show
32 * those.
33 *
34 * <p>
35 * When the view is shown to the user, appears as a floating view over the
36 * application.
37 * <p>
38 * The easiest way to use this class is to call one of the static methods that
39 * constructs everything you need and returns a new OnScreenHint object.
40 */
41public class OnScreenHint {
42    static final String TAG = "OnScreenHint";
43    static final boolean LOCAL_LOGV = false;
44
45    final Context mContext;
46    int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
47    int mX, mY;
48    float mHorizontalMargin;
49    float mVerticalMargin;
50    View mView;
51    View mNextView;
52
53    private final WindowManager.LayoutParams mParams =
54            new WindowManager.LayoutParams();
55    private final WindowManager mWM;
56    private final Handler mHandler = new Handler();
57
58    /**
59     * Construct an empty OnScreenHint object.  You must call {@link #setView}
60     * before you can call {@link #show}.
61     *
62     * @param context  The context to use.  Usually your
63     *                 {@link android.app.Application} or
64     *                 {@link android.app.Activity} object.
65     */
66    public OnScreenHint(Context context) {
67        mContext = context;
68        mWM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
69        mY = context.getResources().getDimensionPixelSize(
70                R.dimen.hint_y_offset);
71
72        mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
73        mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
74        mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
75                | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
76        mParams.format = PixelFormat.TRANSLUCENT;
77        mParams.windowAnimations = R.style.Animation_OnScreenHint;
78        mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
79        mParams.setTitle("OnScreenHint");
80    }
81
82    /**
83     * Show the view on the screen.
84     */
85    public void show() {
86        if (mNextView == null) {
87            throw new RuntimeException("setView must have been called");
88        }
89        mHandler.post(mShow);
90    }
91
92    /**
93     * Close the view if it's showing.
94     */
95    public void cancel() {
96        mHandler.post(mHide);
97    }
98
99    /**
100     * Set the view to show.
101     * @see #getView
102     */
103    public void setView(View view) {
104        mNextView = view;
105    }
106
107    /**
108     * Return the view.
109     * @see #setView
110     */
111    public View getView() {
112        return mNextView;
113    }
114
115    /**
116     * Set the margins of the view.
117     *
118     * @param horizontalMargin The horizontal margin, in percentage of the
119     *        container width, between the container's edges and the
120     *        notification
121     * @param verticalMargin The vertical margin, in percentage of the
122     *        container height, between the container's edges and the
123     *        notification
124     */
125    public void setMargin(float horizontalMargin, float verticalMargin) {
126        mHorizontalMargin = horizontalMargin;
127        mVerticalMargin = verticalMargin;
128    }
129
130    /**
131     * Return the horizontal margin.
132     */
133    public float getHorizontalMargin() {
134        return mHorizontalMargin;
135    }
136
137    /**
138     * Return the vertical margin.
139     */
140    public float getVerticalMargin() {
141        return mVerticalMargin;
142    }
143
144    /**
145     * Set the location at which the notification should appear on the screen.
146     * @see android.view.Gravity
147     * @see #getGravity
148     */
149    public void setGravity(int gravity, int xOffset, int yOffset) {
150        mGravity = gravity;
151        mX = xOffset;
152        mY = yOffset;
153    }
154
155     /**
156     * Get the location at which the notification should appear on the screen.
157     * @see android.view.Gravity
158     * @see #getGravity
159     */
160    public int getGravity() {
161        return mGravity;
162    }
163
164    /**
165     * Return the X offset in pixels to apply to the gravity's location.
166     */
167    public int getXOffset() {
168        return mX;
169    }
170
171    /**
172     * Return the Y offset in pixels to apply to the gravity's location.
173     */
174    public int getYOffset() {
175        return mY;
176    }
177
178    /**
179     * Make a standard hint that just contains a text view.
180     *
181     * @param context  The context to use.  Usually your
182     *                 {@link android.app.Application} or
183     *                 {@link android.app.Activity} object.
184     * @param text     The text to show.  Can be formatted text.
185     *
186     */
187    public static OnScreenHint makeText(Context context, CharSequence text) {
188        OnScreenHint result = new OnScreenHint(context);
189
190        LayoutInflater inflate =
191                (LayoutInflater) context.getSystemService(
192                Context.LAYOUT_INFLATER_SERVICE);
193        View v = inflate.inflate(R.layout.on_screen_hint, null);
194        TextView tv = (TextView) v.findViewById(R.id.message);
195        tv.setText(text);
196
197        result.mNextView = v;
198
199        return result;
200    }
201
202    /**
203     * Make a standard hint that just contains a text view with the text from a
204     * resource.
205     *
206     * @param context  The context to use.  Usually your
207     *                 {@link android.app.Application} or
208     *                 {@link android.app.Activity} object.
209     * @param resId    The resource id of the string resource to use.  Can be
210     *                 formatted text.
211     *
212     * @throws Resources.NotFoundException if the resource can't be found.
213     */
214    public static OnScreenHint makeText(Context context, int resId)
215                                throws Resources.NotFoundException {
216        return makeText(context, context.getResources().getText(resId));
217    }
218
219    /**
220     * Update the text in a OnScreenHint that was previously created using one
221     * of the makeText() methods.
222     * @param resId The new text for the OnScreenHint.
223     */
224    public void setText(int resId) {
225        setText(mContext.getText(resId));
226    }
227
228    /**
229     * Update the text in a OnScreenHint that was previously created using one
230     * of the makeText() methods.
231     * @param s The new text for the OnScreenHint.
232     */
233    public void setText(CharSequence s) {
234        if (mNextView == null) {
235            throw new RuntimeException("This OnScreenHint was not "
236                    + "created with OnScreenHint.makeText()");
237        }
238        TextView tv = (TextView) mNextView.findViewById(R.id.message);
239        if (tv == null) {
240            throw new RuntimeException("This OnScreenHint was not "
241                    + "created with OnScreenHint.makeText()");
242        }
243        tv.setText(s);
244    }
245
246    private synchronized void handleShow() {
247        if (mView != mNextView) {
248            // remove the old view if necessary
249            handleHide();
250            mView = mNextView;
251            final int gravity = mGravity;
252            mParams.gravity = gravity;
253            if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK)
254                    == Gravity.FILL_HORIZONTAL) {
255                mParams.horizontalWeight = 1.0f;
256            }
257            if ((gravity & Gravity.VERTICAL_GRAVITY_MASK)
258                    == Gravity.FILL_VERTICAL) {
259                mParams.verticalWeight = 1.0f;
260            }
261            mParams.x = mX;
262            mParams.y = mY;
263            mParams.verticalMargin = mVerticalMargin;
264            mParams.horizontalMargin = mHorizontalMargin;
265            if (mView.getParent() != null) {
266                mWM.removeView(mView);
267            }
268            mWM.addView(mView, mParams);
269        }
270    }
271
272    private synchronized void handleHide() {
273        if (mView != null) {
274            // note: checking parent() just to make sure the view has
275            // been added...  i have seen cases where we get here when
276            // the view isn't yet added, so let's try not to crash.
277            if (mView.getParent() != null) {
278                mWM.removeView(mView);
279            }
280            mView = null;
281        }
282    }
283
284    private final Runnable mShow = new Runnable() {
285        public void run() {
286            handleShow();
287        }
288    };
289
290    private final Runnable mHide = new Runnable() {
291        public void run() {
292            handleHide();
293        }
294    };
295}
296
297