blob: f90fc59a33b36d26bda50afede67c9a6ce37c857 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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 android.app;
18
Adam Powelldec9dfd2010-08-09 15:27:54 -070019import com.android.internal.app.ActionBarImpl;
svetoslavganov75986cf2009-05-14 22:28:01 -070020import com.android.internal.policy.PolicyManager;
21
Karl Rosaen53d24af2009-07-14 14:58:10 -070022import android.content.ComponentName;
Adam Powell6e346362010-07-23 10:18:23 -070023import android.content.Context;
Karl Rosaen7bafed82009-09-04 11:15:21 -070024import android.content.ContextWrapper;
Adam Powell6e346362010-07-23 10:18:23 -070025import android.content.DialogInterface;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.graphics.drawable.Drawable;
27import android.net.Uri;
Adam Powellc63806d2010-09-23 16:21:30 -070028import android.os.Build;
svetoslavganov75986cf2009-05-14 22:28:01 -070029import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.os.Handler;
31import android.os.Message;
Adam Powell2fbf4de62010-09-30 15:46:46 -070032import android.util.TypedValue;
Adam Powelldec9dfd2010-08-09 15:27:54 -070033import android.view.ActionMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.view.ContextMenu;
Adam Powell6e346362010-07-23 10:18:23 -070035import android.view.ContextMenu.ContextMenuInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.view.ContextThemeWrapper;
37import android.view.Gravity;
38import android.view.KeyEvent;
svetoslavganov75986cf2009-05-14 22:28:01 -070039import android.view.LayoutInflater;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.view.Menu;
41import android.view.MenuItem;
42import android.view.MotionEvent;
43import android.view.View;
Adam Powell6e346362010-07-23 10:18:23 -070044import android.view.View.OnCreateContextMenuListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.view.ViewConfiguration;
46import android.view.ViewGroup;
Adam Powell6e346362010-07-23 10:18:23 -070047import android.view.ViewGroup.LayoutParams;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.view.Window;
49import android.view.WindowManager;
svetoslavganov75986cf2009-05-14 22:28:01 -070050import android.view.accessibility.AccessibilityEvent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051
52import java.lang.ref.WeakReference;
53
54/**
55 * Base class for Dialogs.
56 *
57 * <p>Note: Activities provide a facility to manage the creation, saving and
58 * restoring of dialogs. See {@link Activity#onCreateDialog(int)},
59 * {@link Activity#onPrepareDialog(int, Dialog)},
60 * {@link Activity#showDialog(int)}, and {@link Activity#dismissDialog(int)}. If
61 * these methods are used, {@link #getOwnerActivity()} will return the Activity
62 * that managed this dialog.
63 *
64 * <p>Often you will want to have a Dialog display on top of the current
65 * input method, because there is no reason for it to accept text. You can
66 * do this by setting the {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM
67 * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} window flag (assuming
68 * your Dialog takes input focus, as it the default) with the following code:
69 *
70 * <pre>
71 * getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
72 * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
73 * </pre>
74 */
75public class Dialog implements DialogInterface, Window.Callback,
76 KeyEvent.Callback, OnCreateContextMenuListener {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077 private Activity mOwnerActivity;
78
79 final Context mContext;
80 final WindowManager mWindowManager;
81 Window mWindow;
82 View mDecor;
Adam Powelldec9dfd2010-08-09 15:27:54 -070083 private ActionBarImpl mActionBar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 /**
85 * This field should be made private, so it is hidden from the SDK.
86 * {@hide}
87 */
88 protected boolean mCancelable = true;
svetoslavganov75986cf2009-05-14 22:28:01 -070089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 private Message mCancelMessage;
91 private Message mDismissMessage;
Romain Guy045163a2009-07-14 13:59:33 -070092 private Message mShowMessage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093
94 /**
95 * Whether to cancel the dialog when a touch is received outside of the
96 * window's bounds.
97 */
98 private boolean mCanceledOnTouchOutside = false;
99
100 private OnKeyListener mOnKeyListener;
101
102 private boolean mCreated = false;
103 private boolean mShowing = false;
104
105 private final Thread mUiThread;
106 private final Handler mHandler = new Handler();
107
Romain Guy7883c972010-03-01 16:39:17 -0800108 private static final int DISMISS = 0x43;
109 private static final int CANCEL = 0x44;
110 private static final int SHOW = 0x45;
111
112 private Handler mListenersHandler;
113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 private final Runnable mDismissAction = new Runnable() {
115 public void run() {
116 dismissDialog();
117 }
118 };
119
120 /**
121 * Create a Dialog window that uses the default dialog frame style.
122 *
123 * @param context The Context the Dialog is to run it. In particular, it
124 * uses the window manager and theme in this context to
125 * present its UI.
126 */
127 public Dialog(Context context) {
128 this(context, 0);
129 }
130
131 /**
132 * Create a Dialog window that uses a custom dialog style.
133 *
134 * @param context The Context in which the Dialog should run. In particular, it
135 * uses the window manager and theme from this context to
136 * present its UI.
137 * @param theme A style resource describing the theme to use for the
138 * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style
139 * and Theme Resources</a> for more information about defining and using
140 * styles. This theme is applied on top of the current theme in
141 * <var>context</var>. If 0, the default dialog theme will be used.
142 */
143 public Dialog(Context context, int theme) {
Adam Powell2fbf4de62010-09-30 15:46:46 -0700144 if (theme == 0) {
145 TypedValue outValue = new TypedValue();
146 context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme,
147 outValue, true);
148 theme = outValue.resourceId;
149 }
150
151 mContext = new ContextThemeWrapper(context, theme);
Christian Mehlmaueref367522010-05-31 23:08:30 +0200152 mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 Window w = PolicyManager.makeNewWindow(mContext);
154 mWindow = w;
155 w.setCallback(this);
156 w.setWindowManager(mWindowManager, null, null);
157 w.setGravity(Gravity.CENTER);
158 mUiThread = Thread.currentThread();
Romain Guy045163a2009-07-14 13:59:33 -0700159 mListenersHandler = new ListenersHandler(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 }
161
162 /**
163 * @deprecated
164 * @hide
165 */
166 @Deprecated
167 protected Dialog(Context context, boolean cancelable,
168 Message cancelCallback) {
169 this(context);
170 mCancelable = cancelable;
171 mCancelMessage = cancelCallback;
172 }
173
174 protected Dialog(Context context, boolean cancelable,
175 OnCancelListener cancelListener) {
176 this(context);
177 mCancelable = cancelable;
178 setOnCancelListener(cancelListener);
179 }
180
181 /**
182 * Retrieve the Context this Dialog is running in.
183 *
Adam Powellc49c1732010-09-28 16:03:15 -0700184 * @return Context The Context used by the Dialog.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 */
186 public final Context getContext() {
187 return mContext;
188 }
189
190 /**
Adam Powelldec9dfd2010-08-09 15:27:54 -0700191 * Retrieve the {@link ActionBar} attached to this dialog, if present.
192 *
193 * @return The ActionBar attached to the dialog or null if no ActionBar is present.
194 */
195 public ActionBar getActionBar() {
196 return mActionBar;
197 }
198
199 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 * Sets the Activity that owns this dialog. An example use: This Dialog will
201 * use the suggested volume control stream of the Activity.
202 *
203 * @param activity The Activity that owns this dialog.
204 */
205 public final void setOwnerActivity(Activity activity) {
206 mOwnerActivity = activity;
207
208 getWindow().setVolumeControlStream(mOwnerActivity.getVolumeControlStream());
209 }
210
211 /**
212 * Returns the Activity that owns this Dialog. For example, if
213 * {@link Activity#showDialog(int)} is used to show this Dialog, that
214 * Activity will be the owner (by default). Depending on how this dialog was
215 * created, this may return null.
216 *
217 * @return The Activity that owns this Dialog.
218 */
219 public final Activity getOwnerActivity() {
220 return mOwnerActivity;
221 }
222
223 /**
224 * @return Whether the dialog is currently showing.
225 */
226 public boolean isShowing() {
227 return mShowing;
228 }
229
230 /**
231 * Start the dialog and display it on screen. The window is placed in the
232 * application layer and opaque. Note that you should not override this
233 * method to do initialization when the dialog is shown, instead implement
234 * that in {@link #onStart}.
235 */
236 public void show() {
237 if (mShowing) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700238 if (mDecor != null) {
Adam Powelle67a9dc2010-08-17 17:28:56 -0700239 if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
240 mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
241 }
svetoslavganov75986cf2009-05-14 22:28:01 -0700242 mDecor.setVisibility(View.VISIBLE);
243 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 return;
245 }
246
247 if (!mCreated) {
248 dispatchOnCreate(null);
249 }
250
251 onStart();
252 mDecor = mWindow.getDecorView();
Adam Powelldec9dfd2010-08-09 15:27:54 -0700253
254 if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
255 mActionBar = new ActionBarImpl(this);
256 }
257
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 WindowManager.LayoutParams l = mWindow.getAttributes();
259 if ((l.softInputMode
260 & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
261 WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
262 nl.copyFrom(l);
263 nl.softInputMode |=
264 WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
265 l = nl;
266 }
Romain Guy045163a2009-07-14 13:59:33 -0700267
Romain Guy7eec2bc2010-03-29 13:00:07 -0700268 try {
269 mWindowManager.addView(mDecor, l);
270 mShowing = true;
271
272 sendShowMessage();
273 } finally {
274 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 }
276
277 /**
278 * Hide the dialog, but do not dismiss it.
279 */
280 public void hide() {
svetoslavganov75986cf2009-05-14 22:28:01 -0700281 if (mDecor != null) {
282 mDecor.setVisibility(View.GONE);
283 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 }
285
286 /**
287 * Dismiss this dialog, removing it from the screen. This method can be
288 * invoked safely from any thread. Note that you should not override this
289 * method to do cleanup when the dialog is dismissed, instead implement
290 * that in {@link #onStop}.
291 */
292 public void dismiss() {
293 if (Thread.currentThread() != mUiThread) {
294 mHandler.post(mDismissAction);
295 } else {
296 mDismissAction.run();
297 }
298 }
299
300 private void dismissDialog() {
Romain Guy08a4ac32010-03-16 11:40:40 -0700301 if (mDecor == null || !mShowing) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 return;
303 }
304
Romain Guyd2671e12010-03-11 18:06:42 -0800305 try {
306 mWindowManager.removeView(mDecor);
307 } finally {
308 mDecor = null;
309 mWindow.closeAllPanels();
310 onStop();
311 mShowing = false;
312
313 sendDismissMessage();
314 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 }
316
317 private void sendDismissMessage() {
318 if (mDismissMessage != null) {
319 // Obtain a new message so this dialog can be re-used
320 Message.obtain(mDismissMessage).sendToTarget();
321 }
322 }
svetoslavganov75986cf2009-05-14 22:28:01 -0700323
Romain Guy045163a2009-07-14 13:59:33 -0700324 private void sendShowMessage() {
325 if (mShowMessage != null) {
326 // Obtain a new message so this dialog can be re-used
327 Message.obtain(mShowMessage).sendToTarget();
328 }
329 }
330
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800331 // internal method to make sure mcreated is set properly without requiring
332 // users to call through to super in onCreate
333 void dispatchOnCreate(Bundle savedInstanceState) {
Romain Guy6de4aed2009-07-08 10:54:45 -0700334 if (!mCreated) {
335 onCreate(savedInstanceState);
336 mCreated = true;
337 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 }
339
340 /**
Chet Haase49afa5b2010-08-23 11:39:53 -0700341 * Similar to {@link Activity#onCreate}, you should initialize your dialog
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800342 * in this method, including calling {@link #setContentView}.
343 * @param savedInstanceState If this dialog is being reinitalized after a
344 * the hosting activity was previously shut down, holds the result from
345 * the most recent call to {@link #onSaveInstanceState}, or null if this
346 * is the first time.
347 */
348 protected void onCreate(Bundle savedInstanceState) {
349 }
350
351 /**
352 * Called when the dialog is starting.
353 */
354 protected void onStart() {
355 }
356
357 /**
358 * Called to tell you that you're stopping.
359 */
360 protected void onStop() {
361 }
362
363 private static final String DIALOG_SHOWING_TAG = "android:dialogShowing";
364 private static final String DIALOG_HIERARCHY_TAG = "android:dialogHierarchy";
365
366 /**
367 * Saves the state of the dialog into a bundle.
368 *
369 * The default implementation saves the state of its view hierarchy, so you'll
370 * likely want to call through to super if you override this to save additional
371 * state.
372 * @return A bundle with the state of the dialog.
373 */
374 public Bundle onSaveInstanceState() {
375 Bundle bundle = new Bundle();
376 bundle.putBoolean(DIALOG_SHOWING_TAG, mShowing);
377 if (mCreated) {
378 bundle.putBundle(DIALOG_HIERARCHY_TAG, mWindow.saveHierarchyState());
379 }
380 return bundle;
381 }
382
383 /**
384 * Restore the state of the dialog from a previously saved bundle.
385 *
386 * The default implementation restores the state of the dialog's view
387 * hierarchy that was saved in the default implementation of {@link #onSaveInstanceState()},
388 * so be sure to call through to super when overriding unless you want to
389 * do all restoring of state yourself.
390 * @param savedInstanceState The state of the dialog previously saved by
391 * {@link #onSaveInstanceState()}.
392 */
393 public void onRestoreInstanceState(Bundle savedInstanceState) {
394 final Bundle dialogHierarchyState = savedInstanceState.getBundle(DIALOG_HIERARCHY_TAG);
395 if (dialogHierarchyState == null) {
396 // dialog has never been shown, or onCreated, nothing to restore.
397 return;
398 }
399 dispatchOnCreate(savedInstanceState);
400 mWindow.restoreHierarchyState(dialogHierarchyState);
401 if (savedInstanceState.getBoolean(DIALOG_SHOWING_TAG)) {
402 show();
403 }
404 }
405
406 /**
407 * Retrieve the current Window for the activity. This can be used to
408 * directly access parts of the Window API that are not available
409 * through Activity/Screen.
410 *
411 * @return Window The current window, or null if the activity is not
412 * visual.
413 */
414 public Window getWindow() {
415 return mWindow;
416 }
417
418 /**
419 * Call {@link android.view.Window#getCurrentFocus} on the
420 * Window if this Activity to return the currently focused view.
421 *
422 * @return View The current View with focus or null.
423 *
424 * @see #getWindow
425 * @see android.view.Window#getCurrentFocus
426 */
427 public View getCurrentFocus() {
428 return mWindow != null ? mWindow.getCurrentFocus() : null;
429 }
430
431 /**
432 * Finds a view that was identified by the id attribute from the XML that
433 * was processed in {@link #onStart}.
434 *
435 * @param id the identifier of the view to find
436 * @return The view if found or null otherwise.
437 */
438 public View findViewById(int id) {
439 return mWindow.findViewById(id);
440 }
441
442 /**
443 * Set the screen content from a layout resource. The resource will be
444 * inflated, adding all top-level views to the screen.
445 *
446 * @param layoutResID Resource ID to be inflated.
447 */
448 public void setContentView(int layoutResID) {
449 mWindow.setContentView(layoutResID);
450 }
451
452 /**
453 * Set the screen content to an explicit view. This view is placed
454 * directly into the screen's view hierarchy. It can itself be a complex
455 * view hierarhcy.
456 *
457 * @param view The desired content to display.
458 */
459 public void setContentView(View view) {
460 mWindow.setContentView(view);
461 }
462
463 /**
464 * Set the screen content to an explicit view. This view is placed
465 * directly into the screen's view hierarchy. It can itself be a complex
466 * view hierarhcy.
467 *
468 * @param view The desired content to display.
469 * @param params Layout parameters for the view.
470 */
471 public void setContentView(View view, ViewGroup.LayoutParams params) {
472 mWindow.setContentView(view, params);
473 }
474
475 /**
476 * Add an additional content view to the screen. Added after any existing
477 * ones in the screen -- existing views are NOT removed.
478 *
479 * @param view The desired content to display.
480 * @param params Layout parameters for the view.
481 */
482 public void addContentView(View view, ViewGroup.LayoutParams params) {
483 mWindow.addContentView(view, params);
484 }
485
486 /**
487 * Set the title text for this dialog's window.
488 *
489 * @param title The new text to display in the title.
490 */
491 public void setTitle(CharSequence title) {
492 mWindow.setTitle(title);
493 mWindow.getAttributes().setTitle(title);
494 }
495
496 /**
497 * Set the title text for this dialog's window. The text is retrieved
498 * from the resources with the supplied identifier.
499 *
500 * @param titleId the title's text resource identifier
501 */
502 public void setTitle(int titleId) {
503 setTitle(mContext.getText(titleId));
504 }
505
506 /**
507 * A key was pressed down.
508 *
509 * <p>If the focused view didn't want this event, this method is called.
510 *
Dianne Hackborn83fe3f52009-09-12 23:38:30 -0700511 * <p>The default implementation consumed the KEYCODE_BACK to later
512 * handle it in {@link #onKeyUp}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 *
514 * @see #onKeyUp
515 * @see android.view.KeyEvent
516 */
517 public boolean onKeyDown(int keyCode, KeyEvent event) {
518 if (keyCode == KeyEvent.KEYCODE_BACK) {
Dianne Hackborn83fe3f52009-09-12 23:38:30 -0700519 event.startTracking();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 return true;
521 }
522
523 return false;
524 }
525
526 /**
Dianne Hackborn83fe3f52009-09-12 23:38:30 -0700527 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent)
528 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle
529 * the event).
530 */
531 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
532 return false;
533 }
534
535 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 * A key was released.
537 *
Dianne Hackborn83fe3f52009-09-12 23:38:30 -0700538 * <p>The default implementation handles KEYCODE_BACK to close the
539 * dialog.
540 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 * @see #onKeyDown
542 * @see KeyEvent
543 */
544 public boolean onKeyUp(int keyCode, KeyEvent event) {
Dianne Hackborn83fe3f52009-09-12 23:38:30 -0700545 if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
546 && !event.isCanceled()) {
547 onBackPressed();
548 return true;
549 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 return false;
551 }
552
553 /**
554 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent)
555 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle
556 * the event).
557 */
558 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
559 return false;
560 }
561
562 /**
Dianne Hackborn83fe3f52009-09-12 23:38:30 -0700563 * Called when the dialog has detected the user's press of the back
564 * key. The default implementation simply cancels the dialog (only if
565 * it is cancelable), but you can override this to do whatever you want.
566 */
567 public void onBackPressed() {
568 if (mCancelable) {
569 cancel();
570 }
571 }
572
573 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 * Called when a touch screen event was not handled by any of the views
575 * under it. This is most useful to process touch events that happen outside
576 * of your window bounds, where there is no view to receive it.
577 *
578 * @param event The touch screen event being processed.
579 * @return Return true if you have consumed the event, false if you haven't.
580 * The default implementation will cancel the dialog when a touch
581 * happens outside of the window bounds.
582 */
583 public boolean onTouchEvent(MotionEvent event) {
584 if (mCancelable && mCanceledOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
585 && isOutOfBounds(event)) {
586 cancel();
587 return true;
588 }
589
590 return false;
591 }
592
593 private boolean isOutOfBounds(MotionEvent event) {
594 final int x = (int) event.getX();
595 final int y = (int) event.getY();
596 final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop();
597 final View decorView = getWindow().getDecorView();
598 return (x < -slop) || (y < -slop)
599 || (x > (decorView.getWidth()+slop))
600 || (y > (decorView.getHeight()+slop));
601 }
602
603 /**
604 * Called when the trackball was moved and not handled by any of the
605 * views inside of the activity. So, for example, if the trackball moves
606 * while focus is on a button, you will receive a call here because
607 * buttons do not normally do anything with trackball events. The call
608 * here happens <em>before</em> trackball movements are converted to
609 * DPAD key events, which then get sent back to the view hierarchy, and
610 * will be processed at the point for things like focus navigation.
611 *
612 * @param event The trackball event being processed.
613 *
614 * @return Return true if you have consumed the event, false if you haven't.
615 * The default implementation always returns false.
616 */
617 public boolean onTrackballEvent(MotionEvent event) {
618 return false;
619 }
620
621 public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
622 if (mDecor != null) {
623 mWindowManager.updateViewLayout(mDecor, params);
624 }
625 }
626
627 public void onContentChanged() {
628 }
629
630 public void onWindowFocusChanged(boolean hasFocus) {
631 }
632
Dianne Hackborn3be63c02009-08-20 19:31:38 -0700633 public void onAttachedToWindow() {
634 }
635
636 public void onDetachedFromWindow() {
637 }
638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 /**
640 * Called to process key events. You can override this to intercept all
641 * key events before they are dispatched to the window. Be sure to call
642 * this implementation for key events that should be handled normally.
643 *
644 * @param event The key event.
645 *
646 * @return boolean Return true if this event was consumed.
647 */
648 public boolean dispatchKeyEvent(KeyEvent event) {
649 if ((mOnKeyListener != null) && (mOnKeyListener.onKey(this, event.getKeyCode(), event))) {
650 return true;
651 }
652 if (mWindow.superDispatchKeyEvent(event)) {
653 return true;
654 }
Dianne Hackborn83fe3f52009-09-12 23:38:30 -0700655 return event.dispatch(this, mDecor != null
656 ? mDecor.getKeyDispatcherState() : null, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 }
658
659 /**
660 * Called to process touch screen events. You can override this to
661 * intercept all touch screen events before they are dispatched to the
662 * window. Be sure to call this implementation for touch screen events
663 * that should be handled normally.
664 *
665 * @param ev The touch screen event.
666 *
667 * @return boolean Return true if this event was consumed.
668 */
669 public boolean dispatchTouchEvent(MotionEvent ev) {
670 if (mWindow.superDispatchTouchEvent(ev)) {
671 return true;
672 }
673 return onTouchEvent(ev);
674 }
675
676 /**
677 * Called to process trackball events. You can override this to
678 * intercept all trackball events before they are dispatched to the
679 * window. Be sure to call this implementation for trackball events
680 * that should be handled normally.
681 *
682 * @param ev The trackball event.
683 *
684 * @return boolean Return true if this event was consumed.
685 */
686 public boolean dispatchTrackballEvent(MotionEvent ev) {
687 if (mWindow.superDispatchTrackballEvent(ev)) {
688 return true;
689 }
690 return onTrackballEvent(ev);
691 }
692
svetoslavganov75986cf2009-05-14 22:28:01 -0700693 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
694 event.setClassName(getClass().getName());
695 event.setPackageName(mContext.getPackageName());
696
697 LayoutParams params = getWindow().getAttributes();
Romain Guy980a9382010-01-08 15:06:28 -0800698 boolean isFullScreen = (params.width == LayoutParams.MATCH_PARENT) &&
699 (params.height == LayoutParams.MATCH_PARENT);
svetoslavganov75986cf2009-05-14 22:28:01 -0700700 event.setFullScreen(isFullScreen);
701
702 return false;
703 }
704
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 /**
706 * @see Activity#onCreatePanelView(int)
707 */
708 public View onCreatePanelView(int featureId) {
709 return null;
710 }
711
712 /**
713 * @see Activity#onCreatePanelMenu(int, Menu)
714 */
715 public boolean onCreatePanelMenu(int featureId, Menu menu) {
716 if (featureId == Window.FEATURE_OPTIONS_PANEL) {
717 return onCreateOptionsMenu(menu);
718 }
719
720 return false;
721 }
722
723 /**
724 * @see Activity#onPreparePanel(int, View, Menu)
725 */
726 public boolean onPreparePanel(int featureId, View view, Menu menu) {
727 if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) {
728 boolean goforit = onPrepareOptionsMenu(menu);
729 return goforit && menu.hasVisibleItems();
730 }
731 return true;
732 }
733
734 /**
735 * @see Activity#onMenuOpened(int, Menu)
736 */
737 public boolean onMenuOpened(int featureId, Menu menu) {
Adam Powell8515ee82010-11-30 14:09:55 -0800738 if (featureId == Window.FEATURE_ACTION_BAR) {
739 mActionBar.dispatchMenuVisibilityChanged(true);
740 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 return true;
742 }
743
744 /**
745 * @see Activity#onMenuItemSelected(int, MenuItem)
746 */
747 public boolean onMenuItemSelected(int featureId, MenuItem item) {
748 return false;
749 }
750
751 /**
752 * @see Activity#onPanelClosed(int, Menu)
753 */
754 public void onPanelClosed(int featureId, Menu menu) {
Adam Powell8515ee82010-11-30 14:09:55 -0800755 if (featureId == Window.FEATURE_ACTION_BAR) {
756 mActionBar.dispatchMenuVisibilityChanged(false);
757 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 }
759
760 /**
761 * It is usually safe to proxy this call to the owner activity's
762 * {@link Activity#onCreateOptionsMenu(Menu)} if the client desires the same
763 * menu for this Dialog.
764 *
765 * @see Activity#onCreateOptionsMenu(Menu)
766 * @see #getOwnerActivity()
767 */
768 public boolean onCreateOptionsMenu(Menu menu) {
769 return true;
770 }
771
772 /**
773 * It is usually safe to proxy this call to the owner activity's
774 * {@link Activity#onPrepareOptionsMenu(Menu)} if the client desires the
775 * same menu for this Dialog.
776 *
777 * @see Activity#onPrepareOptionsMenu(Menu)
778 * @see #getOwnerActivity()
779 */
780 public boolean onPrepareOptionsMenu(Menu menu) {
781 return true;
782 }
783
784 /**
785 * @see Activity#onOptionsItemSelected(MenuItem)
786 */
787 public boolean onOptionsItemSelected(MenuItem item) {
788 return false;
789 }
790
791 /**
792 * @see Activity#onOptionsMenuClosed(Menu)
793 */
794 public void onOptionsMenuClosed(Menu menu) {
795 }
796
797 /**
798 * @see Activity#openOptionsMenu()
799 */
800 public void openOptionsMenu() {
801 mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, null);
802 }
803
804 /**
805 * @see Activity#closeOptionsMenu()
806 */
807 public void closeOptionsMenu() {
808 mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL);
809 }
810
811 /**
Adam Powelle67a9dc2010-08-17 17:28:56 -0700812 * @see Activity#invalidateOptionsMenu()
813 */
814 public void invalidateOptionsMenu() {
815 mWindow.invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL);
816 }
817
818 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 * @see Activity#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)
820 */
821 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
822 }
823
824 /**
825 * @see Activity#registerForContextMenu(View)
826 */
827 public void registerForContextMenu(View view) {
828 view.setOnCreateContextMenuListener(this);
829 }
830
831 /**
832 * @see Activity#unregisterForContextMenu(View)
833 */
834 public void unregisterForContextMenu(View view) {
835 view.setOnCreateContextMenuListener(null);
836 }
837
838 /**
839 * @see Activity#openContextMenu(View)
840 */
841 public void openContextMenu(View view) {
842 view.showContextMenu();
843 }
844
845 /**
846 * @see Activity#onContextItemSelected(MenuItem)
847 */
848 public boolean onContextItemSelected(MenuItem item) {
849 return false;
850 }
851
852 /**
853 * @see Activity#onContextMenuClosed(Menu)
854 */
855 public void onContextMenuClosed(Menu menu) {
856 }
857
858 /**
859 * This hook is called when the user signals the desire to start a search.
860 */
861 public boolean onSearchRequested() {
Karl Rosaen53d24af2009-07-14 14:58:10 -0700862 final SearchManager searchManager = (SearchManager) mContext
863 .getSystemService(Context.SEARCH_SERVICE);
864
Bjorn Bringertb8144a92010-02-22 20:48:57 +0000865 // associate search with owner activity
Karl Rosaen7bafed82009-09-04 11:15:21 -0700866 final ComponentName appName = getAssociatedActivity();
Bjorn Bringertb8144a92010-02-22 20:48:57 +0000867 if (appName != null) {
868 searchManager.startSearch(null, false, appName, null, false);
869 dismiss();
870 return true;
871 } else {
872 return false;
873 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 }
875
Adam Powelldebf3be2010-11-15 18:58:48 -0800876 public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
Adam Powelldec9dfd2010-08-09 15:27:54 -0700877 if (mActionBar != null) {
878 return mActionBar.startActionMode(callback);
879 }
Adam Powell6e346362010-07-23 10:18:23 -0700880 return null;
881 }
882
Adam Powelldebf3be2010-11-15 18:58:48 -0800883 public void onActionModeStarted(ActionMode mode) {
884 }
885
886 public void onActionModeFinished(ActionMode mode) {
887 }
888
Karl Rosaen7bafed82009-09-04 11:15:21 -0700889 /**
Adam Powelldec9dfd2010-08-09 15:27:54 -0700890 * @return The activity associated with this dialog, or null if there is no associated activity.
Karl Rosaen7bafed82009-09-04 11:15:21 -0700891 */
892 private ComponentName getAssociatedActivity() {
893 Activity activity = mOwnerActivity;
894 Context context = getContext();
895 while (activity == null && context != null) {
896 if (context instanceof Activity) {
897 activity = (Activity) context; // found it!
898 } else {
899 context = (context instanceof ContextWrapper) ?
900 ((ContextWrapper) context).getBaseContext() : // unwrap one level
901 null; // done
902 }
903 }
904 return activity == null ? null : activity.getComponentName();
905 }
906
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907
908 /**
909 * Request that key events come to this dialog. Use this if your
910 * dialog has no views with focus, but the dialog still wants
911 * a chance to process key events.
912 *
913 * @param get true if the dialog should receive key events, false otherwise
914 * @see android.view.Window#takeKeyEvents
915 */
916 public void takeKeyEvents(boolean get) {
917 mWindow.takeKeyEvents(get);
918 }
919
920 /**
921 * Enable extended window features. This is a convenience for calling
922 * {@link android.view.Window#requestFeature getWindow().requestFeature()}.
923 *
924 * @param featureId The desired feature as defined in
925 * {@link android.view.Window}.
926 * @return Returns true if the requested feature is supported and now
927 * enabled.
928 *
929 * @see android.view.Window#requestFeature
930 */
931 public final boolean requestWindowFeature(int featureId) {
932 return getWindow().requestFeature(featureId);
933 }
934
935 /**
936 * Convenience for calling
937 * {@link android.view.Window#setFeatureDrawableResource}.
938 */
939 public final void setFeatureDrawableResource(int featureId, int resId) {
940 getWindow().setFeatureDrawableResource(featureId, resId);
941 }
942
943 /**
944 * Convenience for calling
945 * {@link android.view.Window#setFeatureDrawableUri}.
946 */
947 public final void setFeatureDrawableUri(int featureId, Uri uri) {
948 getWindow().setFeatureDrawableUri(featureId, uri);
949 }
950
951 /**
952 * Convenience for calling
953 * {@link android.view.Window#setFeatureDrawable(int, Drawable)}.
954 */
955 public final void setFeatureDrawable(int featureId, Drawable drawable) {
956 getWindow().setFeatureDrawable(featureId, drawable);
957 }
958
959 /**
960 * Convenience for calling
961 * {@link android.view.Window#setFeatureDrawableAlpha}.
962 */
963 public final void setFeatureDrawableAlpha(int featureId, int alpha) {
964 getWindow().setFeatureDrawableAlpha(featureId, alpha);
965 }
966
967 public LayoutInflater getLayoutInflater() {
968 return getWindow().getLayoutInflater();
969 }
970
971 /**
972 * Sets whether this dialog is cancelable with the
973 * {@link KeyEvent#KEYCODE_BACK BACK} key.
974 */
975 public void setCancelable(boolean flag) {
976 mCancelable = flag;
977 }
978
979 /**
980 * Sets whether this dialog is canceled when touched outside the window's
981 * bounds. If setting to true, the dialog is set to be cancelable if not
982 * already set.
983 *
984 * @param cancel Whether the dialog should be canceled when touched outside
985 * the window.
986 */
987 public void setCanceledOnTouchOutside(boolean cancel) {
988 if (cancel && !mCancelable) {
989 mCancelable = true;
990 }
991
992 mCanceledOnTouchOutside = cancel;
993 }
994
995 /**
996 * Cancel the dialog. This is essentially the same as calling {@link #dismiss()}, but it will
997 * also call your {@link DialogInterface.OnCancelListener} (if registered).
998 */
999 public void cancel() {
1000 if (mCancelMessage != null) {
1001
1002 // Obtain a new message so this dialog can be re-used
1003 Message.obtain(mCancelMessage).sendToTarget();
1004 }
1005 dismiss();
1006 }
1007
1008 /**
1009 * Set a listener to be invoked when the dialog is canceled.
1010 * <p>
1011 * This will only be invoked when the dialog is canceled, if the creator
1012 * needs to know when it is dismissed in general, use
1013 * {@link #setOnDismissListener}.
1014 *
1015 * @param listener The {@link DialogInterface.OnCancelListener} to use.
1016 */
1017 public void setOnCancelListener(final OnCancelListener listener) {
1018 if (listener != null) {
Romain Guy045163a2009-07-14 13:59:33 -07001019 mCancelMessage = mListenersHandler.obtainMessage(CANCEL, listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 } else {
1021 mCancelMessage = null;
1022 }
1023 }
1024
1025 /**
1026 * Set a message to be sent when the dialog is canceled.
1027 * @param msg The msg to send when the dialog is canceled.
1028 * @see #setOnCancelListener(android.content.DialogInterface.OnCancelListener)
1029 */
1030 public void setCancelMessage(final Message msg) {
1031 mCancelMessage = msg;
1032 }
1033
1034 /**
1035 * Set a listener to be invoked when the dialog is dismissed.
1036 * @param listener The {@link DialogInterface.OnDismissListener} to use.
1037 */
1038 public void setOnDismissListener(final OnDismissListener listener) {
1039 if (listener != null) {
Romain Guy045163a2009-07-14 13:59:33 -07001040 mDismissMessage = mListenersHandler.obtainMessage(DISMISS, listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001041 } else {
1042 mDismissMessage = null;
1043 }
1044 }
1045
1046 /**
Romain Guy045163a2009-07-14 13:59:33 -07001047 * Sets a listener to be invoked when the dialog is shown.
Ficus Kirkpatrick130a8b72010-01-14 15:39:43 -08001048 * @param listener The {@link DialogInterface.OnShowListener} to use.
Romain Guy045163a2009-07-14 13:59:33 -07001049 */
1050 public void setOnShowListener(OnShowListener listener) {
1051 if (listener != null) {
1052 mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);
1053 } else {
1054 mShowMessage = null;
1055 }
1056 }
1057
1058 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001059 * Set a message to be sent when the dialog is dismissed.
1060 * @param msg The msg to send when the dialog is dismissed.
1061 */
1062 public void setDismissMessage(final Message msg) {
1063 mDismissMessage = msg;
1064 }
1065
1066 /**
1067 * By default, this will use the owner Activity's suggested stream type.
1068 *
1069 * @see Activity#setVolumeControlStream(int)
1070 * @see #setOwnerActivity(Activity)
1071 */
1072 public final void setVolumeControlStream(int streamType) {
1073 getWindow().setVolumeControlStream(streamType);
1074 }
1075
1076 /**
1077 * @see Activity#getVolumeControlStream()
1078 */
1079 public final int getVolumeControlStream() {
1080 return getWindow().getVolumeControlStream();
1081 }
1082
1083 /**
1084 * Sets the callback that will be called if a key is dispatched to the dialog.
1085 */
1086 public void setOnKeyListener(final OnKeyListener onKeyListener) {
1087 mOnKeyListener = onKeyListener;
1088 }
1089
Romain Guy045163a2009-07-14 13:59:33 -07001090 private static final class ListenersHandler extends Handler {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 private WeakReference<DialogInterface> mDialog;
1092
Romain Guy045163a2009-07-14 13:59:33 -07001093 public ListenersHandler(Dialog dialog) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 mDialog = new WeakReference<DialogInterface>(dialog);
1095 }
1096
1097 @Override
1098 public void handleMessage(Message msg) {
1099 switch (msg.what) {
1100 case DISMISS:
1101 ((OnDismissListener) msg.obj).onDismiss(mDialog.get());
1102 break;
1103 case CANCEL:
1104 ((OnCancelListener) msg.obj).onCancel(mDialog.get());
1105 break;
Romain Guy045163a2009-07-14 13:59:33 -07001106 case SHOW:
1107 ((OnShowListener) msg.obj).onShow(mDialog.get());
1108 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001109 }
1110 }
1111 }
1112}