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