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 
17 package com.android.camera;
18 
19 import android.content.Context;
20 import android.graphics.PixelFormat;
21 import android.os.Handler;
22 import android.view.Gravity;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.WindowManager;
26 import android.widget.TextView;
27 
28 import com.android.camera.R;
29 
30 /**
31  * A on-screen hint is a view containing a little message for the user and will
32  * be shown on the screen continuously.  This class helps you create and show
33  * those.
34  *
35  * <p>
36  * When the view is shown to the user, appears as a floating view over the
37  * application.
38  * <p>
39  * The easiest way to use this class is to call one of the static methods that
40  * constructs everything you need and returns a new {@code OnScreenHint} object.
41  */
42 public class OnScreenHint {
43     static final String TAG = "OnScreenHint";
44 
45     int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
46     int mX, mY;
47     float mHorizontalMargin;
48     float mVerticalMargin;
49     View mView;
50     View mNextView;
51 
52     private final WindowManager.LayoutParams mParams =
53             new WindowManager.LayoutParams();
54     private final WindowManager mWM;
55     private final Handler mHandler = new Handler();
56 
57     /**
58      * Construct an empty OnScreenHint object.  You must call {@link #setView}
59      * before you can call {@link #show}.
60      *
61      * @param context  The context to use.  Usually your
62      *                 {@link android.app.Application} or
63      *                 {@link android.app.Activity} object.
64      */
OnScreenHint(Context context)65     public OnScreenHint(Context context) {
66         mWM = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
67         mY = context.getResources().getDimensionPixelSize(
68                 R.dimen.hint_y_offset);
69 
70         mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
71         mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
72         mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
73                 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
74         mParams.format = PixelFormat.TRANSLUCENT;
75         mParams.windowAnimations = R.style.Animation_OnScreenHint;
76         mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
77         mParams.setTitle("OnScreenHint");
78     }
79 
80     /**
81      * Show the view on the screen.
82      */
show()83     public void show() {
84         if (mNextView == null) {
85             throw new RuntimeException("setView must have been called");
86         }
87         mHandler.post(mShow);
88     }
89 
90     /**
91      * Close the view if it's showing.
92      */
cancel()93     public void cancel() {
94         mHandler.post(mHide);
95     }
96 
97     /**
98      * Make a standard hint that just contains a text view.
99      *
100      * @param context  The context to use.  Usually your
101      *                 {@link android.app.Application} or
102      *                 {@link android.app.Activity} object.
103      * @param text     The text to show.  Can be formatted text.
104      *
105      */
makeText(Context context, CharSequence text)106     public static OnScreenHint makeText(Context context, CharSequence text) {
107         OnScreenHint result = new OnScreenHint(context);
108 
109         LayoutInflater inflate =
110                 (LayoutInflater) context.getSystemService(
111                 Context.LAYOUT_INFLATER_SERVICE);
112         View v = inflate.inflate(R.layout.on_screen_hint, null);
113         TextView tv = (TextView) v.findViewById(R.id.message);
114         tv.setText(text);
115 
116         result.mNextView = v;
117 
118         return result;
119     }
120 
121     /**
122      * Update the text in a OnScreenHint that was previously created using one
123      * of the makeText() methods.
124      * @param s The new text for the OnScreenHint.
125      */
setText(CharSequence s)126     public void setText(CharSequence s) {
127         if (mNextView == null) {
128             throw new RuntimeException("This OnScreenHint was not "
129                     + "created with OnScreenHint.makeText()");
130         }
131         TextView tv = (TextView) mNextView.findViewById(R.id.message);
132         if (tv == null) {
133             throw new RuntimeException("This OnScreenHint was not "
134                     + "created with OnScreenHint.makeText()");
135         }
136         tv.setText(s);
137     }
138 
handleShow()139     private synchronized void handleShow() {
140         if (mView != mNextView) {
141             // remove the old view if necessary
142             handleHide();
143             mView = mNextView;
144             final int gravity = mGravity;
145             mParams.gravity = gravity;
146             if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK)
147                     == Gravity.FILL_HORIZONTAL) {
148                 mParams.horizontalWeight = 1.0f;
149             }
150             if ((gravity & Gravity.VERTICAL_GRAVITY_MASK)
151                     == Gravity.FILL_VERTICAL) {
152                 mParams.verticalWeight = 1.0f;
153             }
154             mParams.x = mX;
155             mParams.y = mY;
156             mParams.verticalMargin = mVerticalMargin;
157             mParams.horizontalMargin = mHorizontalMargin;
158             if (mView.getParent() != null) {
159                 mWM.removeView(mView);
160             }
161             mWM.addView(mView, mParams);
162         }
163     }
164 
handleHide()165     private synchronized void handleHide() {
166         if (mView != null) {
167             // note: checking parent() just to make sure the view has
168             // been added...  i have seen cases where we get here when
169             // the view isn't yet added, so let's try not to crash.
170             if (mView.getParent() != null) {
171                 mWM.removeView(mView);
172             }
173             mView = null;
174         }
175     }
176 
177     private final Runnable mShow = new Runnable() {
178         public void run() {
179             handleShow();
180         }
181     };
182 
183     private final Runnable mHide = new Runnable() {
184         public void run() {
185             handleHide();
186         }
187     };
188 }
189 
190