OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / frameworks / base / core / java / android / widget / Toast.java
1 /*
2  * Copyright (C) 2007 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 android.widget;
18
19 import android.app.INotificationManager;
20 import android.app.ITransientNotification;
21 import android.content.Context;
22 import android.content.res.Resources;
23 import android.graphics.PixelFormat;
24 import android.os.Handler;
25 import android.os.RemoteException;
26 import android.os.ServiceManager;
27 import android.util.Log;
28 import android.view.Gravity;
29 import android.view.LayoutInflater;
30 import android.view.View;
31 import android.view.WindowManager;
32 import android.view.WindowManagerImpl;
33
34 /**
35  * A toast is a view containing a quick little message for the user.  The toast class
36  * helps you create and show those.
37  * {@more}
38  *
39  * <p>
40  * When the view is shown to the user, appears as a floating view over the
41  * application.  It will never receive focus.  The user will probably be in the
42  * middle of typing something else.  The idea is to be as unobtrusive as
43  * possible, while still showing the user the information you want them to see.
44  * Two examples are the volume control, and the brief message saying that your
45  * settings have been saved.
46  * <p>
47  * The easiest way to use this class is to call one of the static methods that constructs
48  * everything you need and returns a new Toast object.
49  */ 
50 public class Toast {
51     static final String TAG = "Toast";
52     static final boolean localLOGV = false;
53
54     /**
55      * Show the view or text notification for a short period of time.  This time
56      * could be user-definable.  This is the default.
57      * @see #setDuration
58      */
59     public static final int LENGTH_SHORT = 0;
60
61     /**
62      * Show the view or text notification for a long period of time.  This time
63      * could be user-definable.
64      * @see #setDuration
65      */
66     public static final int LENGTH_LONG = 1;
67
68     final Handler mHandler = new Handler();    
69     final Context mContext;
70     final TN mTN;
71     int mDuration;
72     int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
73     int mX, mY;
74     float mHorizontalMargin;
75     float mVerticalMargin;
76     View mView;
77     View mNextView;
78
79     /**
80      * Construct an empty Toast object.  You must call {@link #setView} before you
81      * can call {@link #show}.
82      *
83      * @param context  The context to use.  Usually your {@link android.app.Application}
84      *                 or {@link android.app.Activity} object.
85      */
86     public Toast(Context context) {
87         mContext = context;
88         mTN = new TN();
89         mY = context.getResources().getDimensionPixelSize(
90                 com.android.internal.R.dimen.toast_y_offset);
91     }
92     
93     /**
94      * Show the view for the specified duration.
95      */
96     public void show() {
97         if (mNextView == null) {
98             throw new RuntimeException("setView must have been called");
99         }
100
101         INotificationManager service = getService();
102
103         String pkg = mContext.getPackageName();
104
105         TN tn = mTN;
106
107         try {
108             service.enqueueToast(pkg, tn, mDuration);
109         } catch (RemoteException e) {
110             // Empty
111         }
112     }
113
114     /**
115      * Close the view if it's showing, or don't show it if it isn't showing yet.
116      * You do not normally have to call this.  Normally view will disappear on its own
117      * after the appropriate duration.
118      */
119     public void cancel() {
120         mTN.hide();
121         // TODO this still needs to cancel the inflight notification if any
122     }
123     
124     /**
125      * Set the view to show.
126      * @see #getView
127      */
128     public void setView(View view) {
129         mNextView = view;
130     }
131
132     /**
133      * Return the view.
134      * @see #setView
135      */
136     public View getView() {
137         return mNextView;
138     }
139
140     /**
141      * Set how long to show the view for.
142      * @see #LENGTH_SHORT
143      * @see #LENGTH_LONG
144      */
145     public void setDuration(int duration) {
146         mDuration = duration;
147     }
148
149     /**
150      * Return the duration.
151      * @see #setDuration
152      */
153     public int getDuration() {
154         return mDuration;
155     }
156     
157     /**
158      * Set the margins of the view.
159      *
160      * @param horizontalMargin The horizontal margin, in percentage of the
161      *        container width, between the container's edges and the
162      *        notification
163      * @param verticalMargin The vertical margin, in percentage of the
164      *        container height, between the container's edges and the
165      *        notification
166      */
167     public void setMargin(float horizontalMargin, float verticalMargin) {
168         mHorizontalMargin = horizontalMargin;
169         mVerticalMargin = verticalMargin;
170     }
171
172     /**
173      * Return the horizontal margin.
174      */
175     public float getHorizontalMargin() {
176         return mHorizontalMargin;
177     }
178
179     /**
180      * Return the vertical margin.
181      */
182     public float getVerticalMargin() {
183         return mVerticalMargin;
184     }
185
186     /**
187      * Set the location at which the notification should appear on the screen.
188      * @see android.view.Gravity
189      * @see #getGravity
190      */
191     public void setGravity(int gravity, int xOffset, int yOffset) {
192         mGravity = gravity;
193         mX = xOffset;
194         mY = yOffset;
195     }
196
197      /**
198      * Get the location at which the notification should appear on the screen.
199      * @see android.view.Gravity
200      * @see #getGravity
201      */
202     public int getGravity() {
203         return mGravity;
204     }
205
206     /**
207      * Return the X offset in pixels to apply to the gravity's location.
208      */
209     public int getXOffset() {
210         return mX;
211     }
212     
213     /**
214      * Return the Y offset in pixels to apply to the gravity's location.
215      */
216     public int getYOffset() {
217         return mY;
218     }
219     
220     /**
221      * Make a standard toast that just contains a text view.
222      *
223      * @param context  The context to use.  Usually your {@link android.app.Application}
224      *                 or {@link android.app.Activity} object.
225      * @param text     The text to show.  Can be formatted text.
226      * @param duration How long to display the message.  Either {@link #LENGTH_SHORT} or
227      *                 {@link #LENGTH_LONG}
228      *
229      */
230     public static Toast makeText(Context context, CharSequence text, int duration) {
231         Toast result = new Toast(context);
232
233         LayoutInflater inflate = (LayoutInflater)
234                 context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
235         View v = inflate.inflate(com.android.internal.R.layout.transient_notification, null);
236         TextView tv = (TextView)v.findViewById(com.android.internal.R.id.message);
237         tv.setText(text);
238         
239         result.mNextView = v;
240         result.mDuration = duration;
241
242         return result;
243     }
244
245     /**
246      * Make a standard toast that just contains a text view with the text from a resource.
247      *
248      * @param context  The context to use.  Usually your {@link android.app.Application}
249      *                 or {@link android.app.Activity} object.
250      * @param resId    The resource id of the string resource to use.  Can be formatted text.
251      * @param duration How long to display the message.  Either {@link #LENGTH_SHORT} or
252      *                 {@link #LENGTH_LONG}
253      *
254      * @throws Resources.NotFoundException if the resource can't be found.
255      */
256     public static Toast makeText(Context context, int resId, int duration)
257                                 throws Resources.NotFoundException {
258         return makeText(context, context.getResources().getText(resId), duration);
259     }
260
261     /**
262      * Update the text in a Toast that was previously created using one of the makeText() methods.
263      * @param resId The new text for the Toast.
264      */
265     public void setText(int resId) {
266         setText(mContext.getText(resId));
267     }
268     
269     /**
270      * Update the text in a Toast that was previously created using one of the makeText() methods.
271      * @param s The new text for the Toast.
272      */
273     public void setText(CharSequence s) {
274         if (mNextView == null) {
275             throw new RuntimeException("This Toast was not created with Toast.makeText()");
276         }
277         TextView tv = (TextView) mNextView.findViewById(com.android.internal.R.id.message);
278         if (tv == null) {
279             throw new RuntimeException("This Toast was not created with Toast.makeText()");
280         }
281         tv.setText(s);
282     }
283
284     // =======================================================================================
285     // All the gunk below is the interaction with the Notification Service, which handles
286     // the proper ordering of these system-wide.
287     // =======================================================================================
288
289     private static INotificationManager sService;
290
291     static private INotificationManager getService() {
292         if (sService != null) {
293             return sService;
294         }
295         sService = INotificationManager.Stub.asInterface(ServiceManager.getService("notification"));
296         return sService;
297     }
298
299     private class TN extends ITransientNotification.Stub {
300         final Runnable mShow = new Runnable() {
301             public void run() {
302                 handleShow();
303             }
304         };
305
306         final Runnable mHide = new Runnable() {
307             public void run() {
308                 handleHide();
309             }
310         };
311
312         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
313         
314         WindowManagerImpl mWM;
315
316         TN() {
317             // XXX This should be changed to use a Dialog, with a Theme.Toast
318             // defined that sets up the layout params appropriately.
319             final WindowManager.LayoutParams params = mParams;
320             params.height = WindowManager.LayoutParams.WRAP_CONTENT;
321             params.width = WindowManager.LayoutParams.WRAP_CONTENT;
322             params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
323                     | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
324                     | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
325             params.format = PixelFormat.TRANSLUCENT;
326             params.windowAnimations = com.android.internal.R.style.Animation_Toast;
327             params.type = WindowManager.LayoutParams.TYPE_TOAST;
328             params.setTitle("Toast");
329         }
330
331         /**
332          * schedule handleShow into the right thread
333          */
334         public void show() {
335             if (localLOGV) Log.v(TAG, "SHOW: " + this);
336             mHandler.post(mShow);
337         }
338
339         /**
340          * schedule handleHide into the right thread
341          */
342         public void hide() {
343             if (localLOGV) Log.v(TAG, "HIDE: " + this);
344             mHandler.post(mHide);
345         }
346
347         public void handleShow() {
348             if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
349                     + " mNextView=" + mNextView);
350             if (mView != mNextView) {
351                 // remove the old view if necessary
352                 handleHide();
353                 mView = mNextView;
354                 mWM = WindowManagerImpl.getDefault();
355                 final int gravity = mGravity;
356                 mParams.gravity = gravity;
357                 if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == Gravity.FILL_HORIZONTAL) {
358                     mParams.horizontalWeight = 1.0f;
359                 }
360                 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
361                     mParams.verticalWeight = 1.0f;
362                 }
363                 mParams.x = mX;
364                 mParams.y = mY;
365                 mParams.verticalMargin = mVerticalMargin;
366                 mParams.horizontalMargin = mHorizontalMargin;
367                 if (mView.getParent() != null) {
368                     if (localLOGV) Log.v(
369                             TAG, "REMOVE! " + mView + " in " + this);
370                     mWM.removeView(mView);
371                 }
372                 if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
373                 mWM.addView(mView, mParams);
374             }
375         }
376
377         public void handleHide() {
378             if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
379             if (mView != null) {
380                 // note: checking parent() just to make sure the view has
381                 // been added...  i have seen cases where we get here when
382                 // the view isn't yet added, so let's try not to crash.
383                 if (mView.getParent() != null) {
384                     if (localLOGV) Log.v(
385                             TAG, "REMOVE! " + mView + " in " + this);
386                     mWM.removeView(mView);
387                 }
388
389                 mView = null;
390             }
391         }
392     }
393 }