2 * Copyright (C) 2007 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package android.widget;
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;
35 * A toast is a view containing a quick little message for the user. The toast class
36 * helps you create and show those.
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.
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.
51 static final String TAG = "Toast";
52 static final boolean localLOGV = false;
55 * Show the view or text notification for a short period of time. This time
56 * could be user-definable. This is the default.
59 public static final int LENGTH_SHORT = 0;
62 * Show the view or text notification for a long period of time. This time
63 * could be user-definable.
66 public static final int LENGTH_LONG = 1;
68 final Handler mHandler = new Handler();
69 final Context mContext;
72 int mGravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
74 float mHorizontalMargin;
75 float mVerticalMargin;
80 * Construct an empty Toast object. You must call {@link #setView} before you
81 * can call {@link #show}.
83 * @param context The context to use. Usually your {@link android.app.Application}
84 * or {@link android.app.Activity} object.
86 public Toast(Context context) {
89 mY = context.getResources().getDimensionPixelSize(
90 com.android.internal.R.dimen.toast_y_offset);
94 * Show the view for the specified duration.
97 if (mNextView == null) {
98 throw new RuntimeException("setView must have been called");
101 INotificationManager service = getService();
103 String pkg = mContext.getPackageName();
108 service.enqueueToast(pkg, tn, mDuration);
109 } catch (RemoteException e) {
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.
119 public void cancel() {
121 // TODO this still needs to cancel the inflight notification if any
125 * Set the view to show.
128 public void setView(View view) {
136 public View getView() {
141 * Set how long to show the view for.
145 public void setDuration(int duration) {
146 mDuration = duration;
150 * Return the duration.
153 public int getDuration() {
158 * Set the margins of the view.
160 * @param horizontalMargin The horizontal margin, in percentage of the
161 * container width, between the container's edges and the
163 * @param verticalMargin The vertical margin, in percentage of the
164 * container height, between the container's edges and the
167 public void setMargin(float horizontalMargin, float verticalMargin) {
168 mHorizontalMargin = horizontalMargin;
169 mVerticalMargin = verticalMargin;
173 * Return the horizontal margin.
175 public float getHorizontalMargin() {
176 return mHorizontalMargin;
180 * Return the vertical margin.
182 public float getVerticalMargin() {
183 return mVerticalMargin;
187 * Set the location at which the notification should appear on the screen.
188 * @see android.view.Gravity
191 public void setGravity(int gravity, int xOffset, int yOffset) {
198 * Get the location at which the notification should appear on the screen.
199 * @see android.view.Gravity
202 public int getGravity() {
207 * Return the X offset in pixels to apply to the gravity's location.
209 public int getXOffset() {
214 * Return the Y offset in pixels to apply to the gravity's location.
216 public int getYOffset() {
221 * Make a standard toast that just contains a text view.
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}
230 public static Toast makeText(Context context, CharSequence text, int duration) {
231 Toast result = new Toast(context);
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);
239 result.mNextView = v;
240 result.mDuration = duration;
246 * Make a standard toast that just contains a text view with the text from a resource.
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}
254 * @throws Resources.NotFoundException if the resource can't be found.
256 public static Toast makeText(Context context, int resId, int duration)
257 throws Resources.NotFoundException {
258 return makeText(context, context.getResources().getText(resId), duration);
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.
265 public void setText(int resId) {
266 setText(mContext.getText(resId));
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.
273 public void setText(CharSequence s) {
274 if (mNextView == null) {
275 throw new RuntimeException("This Toast was not created with Toast.makeText()");
277 TextView tv = (TextView) mNextView.findViewById(com.android.internal.R.id.message);
279 throw new RuntimeException("This Toast was not created with Toast.makeText()");
284 // =======================================================================================
285 // All the gunk below is the interaction with the Notification Service, which handles
286 // the proper ordering of these system-wide.
287 // =======================================================================================
289 private static INotificationManager sService;
291 static private INotificationManager getService() {
292 if (sService != null) {
295 sService = INotificationManager.Stub.asInterface(ServiceManager.getService("notification"));
299 private class TN extends ITransientNotification.Stub {
300 final Runnable mShow = new Runnable() {
306 final Runnable mHide = new Runnable() {
312 private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
314 WindowManagerImpl mWM;
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");
332 * schedule handleShow into the right thread
335 if (localLOGV) Log.v(TAG, "SHOW: " + this);
336 mHandler.post(mShow);
340 * schedule handleHide into the right thread
343 if (localLOGV) Log.v(TAG, "HIDE: " + this);
344 mHandler.post(mHide);
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
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;
360 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.FILL_VERTICAL) {
361 mParams.verticalWeight = 1.0f;
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);
372 if (localLOGV) Log.v(TAG, "ADD! " + mView + " in " + this);
373 mWM.addView(mView, mParams);
377 public void handleHide() {
378 if (localLOGV) Log.v(TAG, "HANDLE HIDE: " + this + " mView=" + mView);
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);