Dialog.java revision 89fc3acd4bfb61c7b578f0c9e713d9ea819604e4
1/* 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 19import com.android.internal.app.ActionBarImpl; 20import com.android.internal.policy.PolicyManager; 21 22import android.content.ComponentName; 23import android.content.Context; 24import android.content.ContextWrapper; 25import android.content.DialogInterface; 26import android.graphics.drawable.Drawable; 27import android.net.Uri; 28import android.os.Bundle; 29import android.os.Handler; 30import android.os.Message; 31import android.util.Log; 32import android.util.TypedValue; 33import android.view.ActionMode; 34import android.view.ContextMenu; 35import android.view.ContextMenu.ContextMenuInfo; 36import android.view.ContextThemeWrapper; 37import android.view.Gravity; 38import android.view.KeyEvent; 39import android.view.LayoutInflater; 40import android.view.Menu; 41import android.view.MenuItem; 42import android.view.MotionEvent; 43import android.view.View; 44import android.view.View.OnCreateContextMenuListener; 45import android.view.ViewGroup; 46import android.view.ViewGroup.LayoutParams; 47import android.view.Window; 48import android.view.WindowManager; 49import android.view.accessibility.AccessibilityEvent; 50 51import java.lang.ref.WeakReference; 52 53/** 54 * Base class for Dialogs. 55 * 56 * <p>Note: Activities provide a facility to manage the creation, saving and 57 * restoring of dialogs. See {@link Activity#onCreateDialog(int)}, 58 * {@link Activity#onPrepareDialog(int, Dialog)}, 59 * {@link Activity#showDialog(int)}, and {@link Activity#dismissDialog(int)}. If 60 * these methods are used, {@link #getOwnerActivity()} will return the Activity 61 * that managed this dialog. 62 * 63 * <p>Often you will want to have a Dialog display on top of the current 64 * input method, because there is no reason for it to accept text. You can 65 * do this by setting the {@link WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM 66 * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM} window flag (assuming 67 * your Dialog takes input focus, as it the default) with the following code: 68 * 69 * <pre> 70 * getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, 71 * WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);</pre> 72 * 73 * <div class="special reference"> 74 * <h3>Developer Guides</h3> 75 * <p>For more information about creating dialogs, read the 76 * <a href="{@docRoot}guide/topics/ui/dialogs.html">Dialogs</a> developer guide.</p> 77 * </div> 78 */ 79public class Dialog implements DialogInterface, Window.Callback, 80 KeyEvent.Callback, OnCreateContextMenuListener { 81 private static final String TAG = "Dialog"; 82 private Activity mOwnerActivity; 83 84 final Context mContext; 85 final WindowManager mWindowManager; 86 Window mWindow; 87 View mDecor; 88 private ActionBarImpl mActionBar; 89 /** 90 * This field should be made private, so it is hidden from the SDK. 91 * {@hide} 92 */ 93 protected boolean mCancelable = true; 94 95 private String mCancelAndDismissTaken; 96 private Message mCancelMessage; 97 private Message mDismissMessage; 98 private Message mShowMessage; 99 100 private OnKeyListener mOnKeyListener; 101 102 private boolean mCreated = false; 103 private boolean mShowing = false; 104 private boolean mCanceled = false; 105 106 private final Thread mUiThread; 107 private final Handler mHandler = new Handler(); 108 109 private static final int DISMISS = 0x43; 110 private static final int CANCEL = 0x44; 111 private static final int SHOW = 0x45; 112 113 private Handler mListenersHandler; 114 115 private ActionMode mActionMode; 116 117 private final Runnable mDismissAction = new Runnable() { 118 public void run() { 119 dismissDialog(); 120 } 121 }; 122 123 /** 124 * Create a Dialog window that uses the default dialog frame style. 125 * 126 * @param context The Context the Dialog is to run it. In particular, it 127 * uses the window manager and theme in this context to 128 * present its UI. 129 */ 130 public Dialog(Context context) { 131 this(context, 0, true); 132 } 133 134 /** 135 * Create a Dialog window that uses a custom dialog style. 136 * 137 * @param context The Context in which the Dialog should run. In particular, it 138 * uses the window manager and theme from this context to 139 * present its UI. 140 * @param theme A style resource describing the theme to use for the 141 * window. See <a href="{@docRoot}guide/topics/resources/available-resources.html#stylesandthemes">Style 142 * and Theme Resources</a> for more information about defining and using 143 * styles. This theme is applied on top of the current theme in 144 * <var>context</var>. If 0, the default dialog theme will be used. 145 */ 146 public Dialog(Context context, int theme) { 147 this(context, theme, true); 148 } 149 150 Dialog(Context context, int theme, boolean createContextWrapper) { 151 if (theme == 0) { 152 TypedValue outValue = new TypedValue(); 153 context.getTheme().resolveAttribute(com.android.internal.R.attr.dialogTheme, 154 outValue, true); 155 theme = outValue.resourceId; 156 } 157 158 mContext = createContextWrapper ? new ContextThemeWrapper(context, theme) : context; 159 mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); 160 Window w = PolicyManager.makeNewWindow(mContext); 161 mWindow = w; 162 w.setCallback(this); 163 w.setWindowManager(mWindowManager, null, null); 164 w.setGravity(Gravity.CENTER); 165 mUiThread = Thread.currentThread(); 166 mListenersHandler = new ListenersHandler(this); 167 } 168 169 /** 170 * @deprecated 171 * @hide 172 */ 173 @Deprecated 174 protected Dialog(Context context, boolean cancelable, 175 Message cancelCallback) { 176 this(context); 177 mCancelable = cancelable; 178 mCancelMessage = cancelCallback; 179 } 180 181 protected Dialog(Context context, boolean cancelable, 182 OnCancelListener cancelListener) { 183 this(context); 184 mCancelable = cancelable; 185 setOnCancelListener(cancelListener); 186 } 187 188 /** 189 * Retrieve the Context this Dialog is running in. 190 * 191 * @return Context The Context used by the Dialog. 192 */ 193 public final Context getContext() { 194 return mContext; 195 } 196 197 /** 198 * Retrieve the {@link ActionBar} attached to this dialog, if present. 199 * 200 * @return The ActionBar attached to the dialog or null if no ActionBar is present. 201 */ 202 public ActionBar getActionBar() { 203 return mActionBar; 204 } 205 206 /** 207 * Sets the Activity that owns this dialog. An example use: This Dialog will 208 * use the suggested volume control stream of the Activity. 209 * 210 * @param activity The Activity that owns this dialog. 211 */ 212 public final void setOwnerActivity(Activity activity) { 213 mOwnerActivity = activity; 214 215 getWindow().setVolumeControlStream(mOwnerActivity.getVolumeControlStream()); 216 } 217 218 /** 219 * Returns the Activity that owns this Dialog. For example, if 220 * {@link Activity#showDialog(int)} is used to show this Dialog, that 221 * Activity will be the owner (by default). Depending on how this dialog was 222 * created, this may return null. 223 * 224 * @return The Activity that owns this Dialog. 225 */ 226 public final Activity getOwnerActivity() { 227 return mOwnerActivity; 228 } 229 230 /** 231 * @return Whether the dialog is currently showing. 232 */ 233 public boolean isShowing() { 234 return mShowing; 235 } 236 237 /** 238 * Start the dialog and display it on screen. The window is placed in the 239 * application layer and opaque. Note that you should not override this 240 * method to do initialization when the dialog is shown, instead implement 241 * that in {@link #onStart}. 242 */ 243 public void show() { 244 if (mShowing) { 245 if (mDecor != null) { 246 if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { 247 mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR); 248 } 249 mDecor.setVisibility(View.VISIBLE); 250 } 251 return; 252 } 253 254 mCanceled = false; 255 256 if (!mCreated) { 257 dispatchOnCreate(null); 258 } 259 260 onStart(); 261 mDecor = mWindow.getDecorView(); 262 263 if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) { 264 mActionBar = new ActionBarImpl(this); 265 } 266 267 WindowManager.LayoutParams l = mWindow.getAttributes(); 268 if ((l.softInputMode 269 & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) { 270 WindowManager.LayoutParams nl = new WindowManager.LayoutParams(); 271 nl.copyFrom(l); 272 nl.softInputMode |= 273 WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION; 274 l = nl; 275 } 276 277 try { 278 mWindowManager.addView(mDecor, l); 279 mShowing = true; 280 281 sendShowMessage(); 282 } finally { 283 } 284 } 285 286 /** 287 * Hide the dialog, but do not dismiss it. 288 */ 289 public void hide() { 290 if (mDecor != null) { 291 mDecor.setVisibility(View.GONE); 292 } 293 } 294 295 /** 296 * Dismiss this dialog, removing it from the screen. This method can be 297 * invoked safely from any thread. Note that you should not override this 298 * method to do cleanup when the dialog is dismissed, instead implement 299 * that in {@link #onStop}. 300 */ 301 public void dismiss() { 302 if (Thread.currentThread() != mUiThread) { 303 mHandler.post(mDismissAction); 304 } else { 305 mHandler.removeCallbacks(mDismissAction); 306 mDismissAction.run(); 307 } 308 } 309 310 void dismissDialog() { 311 if (mDecor == null || !mShowing) { 312 return; 313 } 314 315 if (mWindow.isDestroyed()) { 316 Log.e(TAG, "Tried to dismissDialog() but the Dialog's window was already destroyed!"); 317 return; 318 } 319 320 try { 321 mWindowManager.removeView(mDecor); 322 } finally { 323 if (mActionMode != null) { 324 mActionMode.finish(); 325 } 326 mDecor = null; 327 mWindow.closeAllPanels(); 328 onStop(); 329 mShowing = false; 330 331 sendDismissMessage(); 332 } 333 } 334 335 private void sendDismissMessage() { 336 if (mDismissMessage != null) { 337 // Obtain a new message so this dialog can be re-used 338 Message.obtain(mDismissMessage).sendToTarget(); 339 } 340 } 341 342 private void sendShowMessage() { 343 if (mShowMessage != null) { 344 // Obtain a new message so this dialog can be re-used 345 Message.obtain(mShowMessage).sendToTarget(); 346 } 347 } 348 349 // internal method to make sure mcreated is set properly without requiring 350 // users to call through to super in onCreate 351 void dispatchOnCreate(Bundle savedInstanceState) { 352 if (!mCreated) { 353 onCreate(savedInstanceState); 354 mCreated = true; 355 } 356 } 357 358 /** 359 * Similar to {@link Activity#onCreate}, you should initialize your dialog 360 * in this method, including calling {@link #setContentView}. 361 * @param savedInstanceState If this dialog is being reinitalized after a 362 * the hosting activity was previously shut down, holds the result from 363 * the most recent call to {@link #onSaveInstanceState}, or null if this 364 * is the first time. 365 */ 366 protected void onCreate(Bundle savedInstanceState) { 367 } 368 369 /** 370 * Called when the dialog is starting. 371 */ 372 protected void onStart() { 373 if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(true); 374 } 375 376 /** 377 * Called to tell you that you're stopping. 378 */ 379 protected void onStop() { 380 if (mActionBar != null) mActionBar.setShowHideAnimationEnabled(false); 381 } 382 383 private static final String DIALOG_SHOWING_TAG = "android:dialogShowing"; 384 private static final String DIALOG_HIERARCHY_TAG = "android:dialogHierarchy"; 385 386 /** 387 * Saves the state of the dialog into a bundle. 388 * 389 * The default implementation saves the state of its view hierarchy, so you'll 390 * likely want to call through to super if you override this to save additional 391 * state. 392 * @return A bundle with the state of the dialog. 393 */ 394 public Bundle onSaveInstanceState() { 395 Bundle bundle = new Bundle(); 396 bundle.putBoolean(DIALOG_SHOWING_TAG, mShowing); 397 if (mCreated) { 398 bundle.putBundle(DIALOG_HIERARCHY_TAG, mWindow.saveHierarchyState()); 399 } 400 return bundle; 401 } 402 403 /** 404 * Restore the state of the dialog from a previously saved bundle. 405 * 406 * The default implementation restores the state of the dialog's view 407 * hierarchy that was saved in the default implementation of {@link #onSaveInstanceState()}, 408 * so be sure to call through to super when overriding unless you want to 409 * do all restoring of state yourself. 410 * @param savedInstanceState The state of the dialog previously saved by 411 * {@link #onSaveInstanceState()}. 412 */ 413 public void onRestoreInstanceState(Bundle savedInstanceState) { 414 final Bundle dialogHierarchyState = savedInstanceState.getBundle(DIALOG_HIERARCHY_TAG); 415 if (dialogHierarchyState == null) { 416 // dialog has never been shown, or onCreated, nothing to restore. 417 return; 418 } 419 dispatchOnCreate(savedInstanceState); 420 mWindow.restoreHierarchyState(dialogHierarchyState); 421 if (savedInstanceState.getBoolean(DIALOG_SHOWING_TAG)) { 422 show(); 423 } 424 } 425 426 /** 427 * Retrieve the current Window for the activity. This can be used to 428 * directly access parts of the Window API that are not available 429 * through Activity/Screen. 430 * 431 * @return Window The current window, or null if the activity is not 432 * visual. 433 */ 434 public Window getWindow() { 435 return mWindow; 436 } 437 438 /** 439 * Call {@link android.view.Window#getCurrentFocus} on the 440 * Window if this Activity to return the currently focused view. 441 * 442 * @return View The current View with focus or null. 443 * 444 * @see #getWindow 445 * @see android.view.Window#getCurrentFocus 446 */ 447 public View getCurrentFocus() { 448 return mWindow != null ? mWindow.getCurrentFocus() : null; 449 } 450 451 /** 452 * Finds a view that was identified by the id attribute from the XML that 453 * was processed in {@link #onStart}. 454 * 455 * @param id the identifier of the view to find 456 * @return The view if found or null otherwise. 457 */ 458 public View findViewById(int id) { 459 return mWindow.findViewById(id); 460 } 461 462 /** 463 * Set the screen content from a layout resource. The resource will be 464 * inflated, adding all top-level views to the screen. 465 * 466 * @param layoutResID Resource ID to be inflated. 467 */ 468 public void setContentView(int layoutResID) { 469 mWindow.setContentView(layoutResID); 470 } 471 472 /** 473 * Set the screen content to an explicit view. This view is placed 474 * directly into the screen's view hierarchy. It can itself be a complex 475 * view hierarhcy. 476 * 477 * @param view The desired content to display. 478 */ 479 public void setContentView(View view) { 480 mWindow.setContentView(view); 481 } 482 483 /** 484 * Set the screen content to an explicit view. This view is placed 485 * directly into the screen's view hierarchy. It can itself be a complex 486 * view hierarhcy. 487 * 488 * @param view The desired content to display. 489 * @param params Layout parameters for the view. 490 */ 491 public void setContentView(View view, ViewGroup.LayoutParams params) { 492 mWindow.setContentView(view, params); 493 } 494 495 /** 496 * Add an additional content view to the screen. Added after any existing 497 * ones in the screen -- existing views are NOT removed. 498 * 499 * @param view The desired content to display. 500 * @param params Layout parameters for the view. 501 */ 502 public void addContentView(View view, ViewGroup.LayoutParams params) { 503 mWindow.addContentView(view, params); 504 } 505 506 /** 507 * Set the title text for this dialog's window. 508 * 509 * @param title The new text to display in the title. 510 */ 511 public void setTitle(CharSequence title) { 512 mWindow.setTitle(title); 513 mWindow.getAttributes().setTitle(title); 514 } 515 516 /** 517 * Set the title text for this dialog's window. The text is retrieved 518 * from the resources with the supplied identifier. 519 * 520 * @param titleId the title's text resource identifier 521 */ 522 public void setTitle(int titleId) { 523 setTitle(mContext.getText(titleId)); 524 } 525 526 /** 527 * A key was pressed down. 528 * 529 * <p>If the focused view didn't want this event, this method is called. 530 * 531 * <p>The default implementation consumed the KEYCODE_BACK to later 532 * handle it in {@link #onKeyUp}. 533 * 534 * @see #onKeyUp 535 * @see android.view.KeyEvent 536 */ 537 public boolean onKeyDown(int keyCode, KeyEvent event) { 538 if (keyCode == KeyEvent.KEYCODE_BACK) { 539 event.startTracking(); 540 return true; 541 } 542 543 return false; 544 } 545 546 /** 547 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 548 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 549 * the event). 550 */ 551 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 552 return false; 553 } 554 555 /** 556 * A key was released. 557 * 558 * <p>The default implementation handles KEYCODE_BACK to close the 559 * dialog. 560 * 561 * @see #onKeyDown 562 * @see KeyEvent 563 */ 564 public boolean onKeyUp(int keyCode, KeyEvent event) { 565 if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking() 566 && !event.isCanceled()) { 567 onBackPressed(); 568 return true; 569 } 570 return false; 571 } 572 573 /** 574 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 575 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 576 * the event). 577 */ 578 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 579 return false; 580 } 581 582 /** 583 * Called when the dialog has detected the user's press of the back 584 * key. The default implementation simply cancels the dialog (only if 585 * it is cancelable), but you can override this to do whatever you want. 586 */ 587 public void onBackPressed() { 588 if (mCancelable) { 589 cancel(); 590 } 591 } 592 593 /** 594 * Called when an key shortcut event is not handled by any of the views in the Dialog. 595 * Override this method to implement global key shortcuts for the Dialog. 596 * Key shortcuts can also be implemented by setting the 597 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 598 * 599 * @param keyCode The value in event.getKeyCode(). 600 * @param event Description of the key event. 601 * @return True if the key shortcut was handled. 602 */ 603 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 604 return false; 605 } 606 607 /** 608 * Called when a touch screen event was not handled by any of the views 609 * under it. This is most useful to process touch events that happen outside 610 * of your window bounds, where there is no view to receive it. 611 * 612 * @param event The touch screen event being processed. 613 * @return Return true if you have consumed the event, false if you haven't. 614 * The default implementation will cancel the dialog when a touch 615 * happens outside of the window bounds. 616 */ 617 public boolean onTouchEvent(MotionEvent event) { 618 if (mCancelable && mShowing && mWindow.shouldCloseOnTouch(mContext, event)) { 619 cancel(); 620 return true; 621 } 622 623 return false; 624 } 625 626 /** 627 * Called when the trackball was moved and not handled by any of the 628 * views inside of the activity. So, for example, if the trackball moves 629 * while focus is on a button, you will receive a call here because 630 * buttons do not normally do anything with trackball events. The call 631 * here happens <em>before</em> trackball movements are converted to 632 * DPAD key events, which then get sent back to the view hierarchy, and 633 * will be processed at the point for things like focus navigation. 634 * 635 * @param event The trackball event being processed. 636 * 637 * @return Return true if you have consumed the event, false if you haven't. 638 * The default implementation always returns false. 639 */ 640 public boolean onTrackballEvent(MotionEvent event) { 641 return false; 642 } 643 644 /** 645 * Called when a generic motion event was not handled by any of the 646 * views inside of the dialog. 647 * <p> 648 * Generic motion events describe joystick movements, mouse hovers, track pad 649 * touches, scroll wheel movements and other input events. The 650 * {@link MotionEvent#getSource() source} of the motion event specifies 651 * the class of input that was received. Implementations of this method 652 * must examine the bits in the source before processing the event. 653 * The following code example shows how this is done. 654 * </p><p> 655 * Generic motion events with source class 656 * {@link android.view.InputDevice#SOURCE_CLASS_POINTER} 657 * are delivered to the view under the pointer. All other generic motion events are 658 * delivered to the focused view. 659 * </p><p> 660 * See {@link View#onGenericMotionEvent(MotionEvent)} for an example of how to 661 * handle this event. 662 * </p> 663 * 664 * @param event The generic motion event being processed. 665 * 666 * @return Return true if you have consumed the event, false if you haven't. 667 * The default implementation always returns false. 668 */ 669 public boolean onGenericMotionEvent(MotionEvent event) { 670 return false; 671 } 672 673 public void onWindowAttributesChanged(WindowManager.LayoutParams params) { 674 if (mDecor != null) { 675 mWindowManager.updateViewLayout(mDecor, params); 676 } 677 } 678 679 public void onContentChanged() { 680 } 681 682 public void onWindowFocusChanged(boolean hasFocus) { 683 } 684 685 public void onAttachedToWindow() { 686 } 687 688 public void onDetachedFromWindow() { 689 } 690 691 /** 692 * Called to process key events. You can override this to intercept all 693 * key events before they are dispatched to the window. Be sure to call 694 * this implementation for key events that should be handled normally. 695 * 696 * @param event The key event. 697 * 698 * @return boolean Return true if this event was consumed. 699 */ 700 public boolean dispatchKeyEvent(KeyEvent event) { 701 if ((mOnKeyListener != null) && (mOnKeyListener.onKey(this, event.getKeyCode(), event))) { 702 return true; 703 } 704 if (mWindow.superDispatchKeyEvent(event)) { 705 return true; 706 } 707 return event.dispatch(this, mDecor != null 708 ? mDecor.getKeyDispatcherState() : null, this); 709 } 710 711 /** 712 * Called to process a key shortcut event. 713 * You can override this to intercept all key shortcut events before they are 714 * dispatched to the window. Be sure to call this implementation for key shortcut 715 * events that should be handled normally. 716 * 717 * @param event The key shortcut event. 718 * @return True if this event was consumed. 719 */ 720 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 721 if (mWindow.superDispatchKeyShortcutEvent(event)) { 722 return true; 723 } 724 return onKeyShortcut(event.getKeyCode(), event); 725 } 726 727 /** 728 * Called to process touch screen events. You can override this to 729 * intercept all touch screen events before they are dispatched to the 730 * window. Be sure to call this implementation for touch screen events 731 * that should be handled normally. 732 * 733 * @param ev The touch screen event. 734 * 735 * @return boolean Return true if this event was consumed. 736 */ 737 public boolean dispatchTouchEvent(MotionEvent ev) { 738 if (mWindow.superDispatchTouchEvent(ev)) { 739 return true; 740 } 741 return onTouchEvent(ev); 742 } 743 744 /** 745 * Called to process trackball events. You can override this to 746 * intercept all trackball events before they are dispatched to the 747 * window. Be sure to call this implementation for trackball events 748 * that should be handled normally. 749 * 750 * @param ev The trackball event. 751 * 752 * @return boolean Return true if this event was consumed. 753 */ 754 public boolean dispatchTrackballEvent(MotionEvent ev) { 755 if (mWindow.superDispatchTrackballEvent(ev)) { 756 return true; 757 } 758 return onTrackballEvent(ev); 759 } 760 761 /** 762 * Called to process generic motion events. You can override this to 763 * intercept all generic motion events before they are dispatched to the 764 * window. Be sure to call this implementation for generic motion events 765 * that should be handled normally. 766 * 767 * @param ev The generic motion event. 768 * 769 * @return boolean Return true if this event was consumed. 770 */ 771 public boolean dispatchGenericMotionEvent(MotionEvent ev) { 772 if (mWindow.superDispatchGenericMotionEvent(ev)) { 773 return true; 774 } 775 return onGenericMotionEvent(ev); 776 } 777 778 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 779 event.setClassName(getClass().getName()); 780 event.setPackageName(mContext.getPackageName()); 781 782 LayoutParams params = getWindow().getAttributes(); 783 boolean isFullScreen = (params.width == LayoutParams.MATCH_PARENT) && 784 (params.height == LayoutParams.MATCH_PARENT); 785 event.setFullScreen(isFullScreen); 786 787 return false; 788 } 789 790 /** 791 * @see Activity#onCreatePanelView(int) 792 */ 793 public View onCreatePanelView(int featureId) { 794 return null; 795 } 796 797 /** 798 * @see Activity#onCreatePanelMenu(int, Menu) 799 */ 800 public boolean onCreatePanelMenu(int featureId, Menu menu) { 801 if (featureId == Window.FEATURE_OPTIONS_PANEL) { 802 return onCreateOptionsMenu(menu); 803 } 804 805 return false; 806 } 807 808 /** 809 * @see Activity#onPreparePanel(int, View, Menu) 810 */ 811 public boolean onPreparePanel(int featureId, View view, Menu menu) { 812 if (featureId == Window.FEATURE_OPTIONS_PANEL && menu != null) { 813 boolean goforit = onPrepareOptionsMenu(menu); 814 return goforit && menu.hasVisibleItems(); 815 } 816 return true; 817 } 818 819 /** 820 * @see Activity#onMenuOpened(int, Menu) 821 */ 822 public boolean onMenuOpened(int featureId, Menu menu) { 823 if (featureId == Window.FEATURE_ACTION_BAR) { 824 mActionBar.dispatchMenuVisibilityChanged(true); 825 } 826 return true; 827 } 828 829 /** 830 * @see Activity#onMenuItemSelected(int, MenuItem) 831 */ 832 public boolean onMenuItemSelected(int featureId, MenuItem item) { 833 return false; 834 } 835 836 /** 837 * @see Activity#onPanelClosed(int, Menu) 838 */ 839 public void onPanelClosed(int featureId, Menu menu) { 840 if (featureId == Window.FEATURE_ACTION_BAR) { 841 mActionBar.dispatchMenuVisibilityChanged(false); 842 } 843 } 844 845 /** 846 * It is usually safe to proxy this call to the owner activity's 847 * {@link Activity#onCreateOptionsMenu(Menu)} if the client desires the same 848 * menu for this Dialog. 849 * 850 * @see Activity#onCreateOptionsMenu(Menu) 851 * @see #getOwnerActivity() 852 */ 853 public boolean onCreateOptionsMenu(Menu menu) { 854 return true; 855 } 856 857 /** 858 * It is usually safe to proxy this call to the owner activity's 859 * {@link Activity#onPrepareOptionsMenu(Menu)} if the client desires the 860 * same menu for this Dialog. 861 * 862 * @see Activity#onPrepareOptionsMenu(Menu) 863 * @see #getOwnerActivity() 864 */ 865 public boolean onPrepareOptionsMenu(Menu menu) { 866 return true; 867 } 868 869 /** 870 * @see Activity#onOptionsItemSelected(MenuItem) 871 */ 872 public boolean onOptionsItemSelected(MenuItem item) { 873 return false; 874 } 875 876 /** 877 * @see Activity#onOptionsMenuClosed(Menu) 878 */ 879 public void onOptionsMenuClosed(Menu menu) { 880 } 881 882 /** 883 * @see Activity#openOptionsMenu() 884 */ 885 public void openOptionsMenu() { 886 mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, null); 887 } 888 889 /** 890 * @see Activity#closeOptionsMenu() 891 */ 892 public void closeOptionsMenu() { 893 mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL); 894 } 895 896 /** 897 * @see Activity#invalidateOptionsMenu() 898 */ 899 public void invalidateOptionsMenu() { 900 mWindow.invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL); 901 } 902 903 /** 904 * @see Activity#onCreateContextMenu(ContextMenu, View, ContextMenuInfo) 905 */ 906 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 907 } 908 909 /** 910 * @see Activity#registerForContextMenu(View) 911 */ 912 public void registerForContextMenu(View view) { 913 view.setOnCreateContextMenuListener(this); 914 } 915 916 /** 917 * @see Activity#unregisterForContextMenu(View) 918 */ 919 public void unregisterForContextMenu(View view) { 920 view.setOnCreateContextMenuListener(null); 921 } 922 923 /** 924 * @see Activity#openContextMenu(View) 925 */ 926 public void openContextMenu(View view) { 927 view.showContextMenu(); 928 } 929 930 /** 931 * @see Activity#onContextItemSelected(MenuItem) 932 */ 933 public boolean onContextItemSelected(MenuItem item) { 934 return false; 935 } 936 937 /** 938 * @see Activity#onContextMenuClosed(Menu) 939 */ 940 public void onContextMenuClosed(Menu menu) { 941 } 942 943 /** 944 * This hook is called when the user signals the desire to start a search. 945 */ 946 public boolean onSearchRequested() { 947 final SearchManager searchManager = (SearchManager) mContext 948 .getSystemService(Context.SEARCH_SERVICE); 949 950 // associate search with owner activity 951 final ComponentName appName = getAssociatedActivity(); 952 if (appName != null && searchManager.getSearchableInfo(appName) != null) { 953 searchManager.startSearch(null, false, appName, null, false); 954 dismiss(); 955 return true; 956 } else { 957 return false; 958 } 959 } 960 961 public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) { 962 if (mActionBar != null) { 963 return mActionBar.startActionMode(callback); 964 } 965 return null; 966 } 967 968 /** 969 * {@inheritDoc} 970 * 971 * Note that if you override this method you should always call through 972 * to the superclass implementation by calling super.onActionModeStarted(mode). 973 */ 974 public void onActionModeStarted(ActionMode mode) { 975 mActionMode = mode; 976 } 977 978 /** 979 * {@inheritDoc} 980 * 981 * Note that if you override this method you should always call through 982 * to the superclass implementation by calling super.onActionModeFinished(mode). 983 */ 984 public void onActionModeFinished(ActionMode mode) { 985 if (mode == mActionMode) { 986 mActionMode = null; 987 } 988 } 989 990 /** 991 * @return The activity associated with this dialog, or null if there is no associated activity. 992 */ 993 private ComponentName getAssociatedActivity() { 994 Activity activity = mOwnerActivity; 995 Context context = getContext(); 996 while (activity == null && context != null) { 997 if (context instanceof Activity) { 998 activity = (Activity) context; // found it! 999 } else { 1000 context = (context instanceof ContextWrapper) ? 1001 ((ContextWrapper) context).getBaseContext() : // unwrap one level 1002 null; // done 1003 } 1004 } 1005 return activity == null ? null : activity.getComponentName(); 1006 } 1007 1008 1009 /** 1010 * Request that key events come to this dialog. Use this if your 1011 * dialog has no views with focus, but the dialog still wants 1012 * a chance to process key events. 1013 * 1014 * @param get true if the dialog should receive key events, false otherwise 1015 * @see android.view.Window#takeKeyEvents 1016 */ 1017 public void takeKeyEvents(boolean get) { 1018 mWindow.takeKeyEvents(get); 1019 } 1020 1021 /** 1022 * Enable extended window features. This is a convenience for calling 1023 * {@link android.view.Window#requestFeature getWindow().requestFeature()}. 1024 * 1025 * @param featureId The desired feature as defined in 1026 * {@link android.view.Window}. 1027 * @return Returns true if the requested feature is supported and now 1028 * enabled. 1029 * 1030 * @see android.view.Window#requestFeature 1031 */ 1032 public final boolean requestWindowFeature(int featureId) { 1033 return getWindow().requestFeature(featureId); 1034 } 1035 1036 /** 1037 * Convenience for calling 1038 * {@link android.view.Window#setFeatureDrawableResource}. 1039 */ 1040 public final void setFeatureDrawableResource(int featureId, int resId) { 1041 getWindow().setFeatureDrawableResource(featureId, resId); 1042 } 1043 1044 /** 1045 * Convenience for calling 1046 * {@link android.view.Window#setFeatureDrawableUri}. 1047 */ 1048 public final void setFeatureDrawableUri(int featureId, Uri uri) { 1049 getWindow().setFeatureDrawableUri(featureId, uri); 1050 } 1051 1052 /** 1053 * Convenience for calling 1054 * {@link android.view.Window#setFeatureDrawable(int, Drawable)}. 1055 */ 1056 public final void setFeatureDrawable(int featureId, Drawable drawable) { 1057 getWindow().setFeatureDrawable(featureId, drawable); 1058 } 1059 1060 /** 1061 * Convenience for calling 1062 * {@link android.view.Window#setFeatureDrawableAlpha}. 1063 */ 1064 public final void setFeatureDrawableAlpha(int featureId, int alpha) { 1065 getWindow().setFeatureDrawableAlpha(featureId, alpha); 1066 } 1067 1068 public LayoutInflater getLayoutInflater() { 1069 return getWindow().getLayoutInflater(); 1070 } 1071 1072 /** 1073 * Sets whether this dialog is cancelable with the 1074 * {@link KeyEvent#KEYCODE_BACK BACK} key. 1075 */ 1076 public void setCancelable(boolean flag) { 1077 mCancelable = flag; 1078 } 1079 1080 /** 1081 * Sets whether this dialog is canceled when touched outside the window's 1082 * bounds. If setting to true, the dialog is set to be cancelable if not 1083 * already set. 1084 * 1085 * @param cancel Whether the dialog should be canceled when touched outside 1086 * the window. 1087 */ 1088 public void setCanceledOnTouchOutside(boolean cancel) { 1089 if (cancel && !mCancelable) { 1090 mCancelable = true; 1091 } 1092 1093 mWindow.setCloseOnTouchOutside(cancel); 1094 } 1095 1096 /** 1097 * Cancel the dialog. This is essentially the same as calling {@link #dismiss()}, but it will 1098 * also call your {@link DialogInterface.OnCancelListener} (if registered). 1099 */ 1100 public void cancel() { 1101 if (!mCanceled && mCancelMessage != null) { 1102 mCanceled = true; 1103 // Obtain a new message so this dialog can be re-used 1104 Message.obtain(mCancelMessage).sendToTarget(); 1105 } 1106 dismiss(); 1107 } 1108 1109 /** 1110 * Set a listener to be invoked when the dialog is canceled. 1111 * <p> 1112 * This will only be invoked when the dialog is canceled, if the creator 1113 * needs to know when it is dismissed in general, use 1114 * {@link #setOnDismissListener}. 1115 * 1116 * @param listener The {@link DialogInterface.OnCancelListener} to use. 1117 */ 1118 public void setOnCancelListener(final OnCancelListener listener) { 1119 if (mCancelAndDismissTaken != null) { 1120 throw new IllegalStateException( 1121 "OnCancelListener is already taken by " 1122 + mCancelAndDismissTaken + " and can not be replaced."); 1123 } 1124 if (listener != null) { 1125 mCancelMessage = mListenersHandler.obtainMessage(CANCEL, listener); 1126 } else { 1127 mCancelMessage = null; 1128 } 1129 } 1130 1131 /** 1132 * Set a message to be sent when the dialog is canceled. 1133 * @param msg The msg to send when the dialog is canceled. 1134 * @see #setOnCancelListener(android.content.DialogInterface.OnCancelListener) 1135 */ 1136 public void setCancelMessage(final Message msg) { 1137 mCancelMessage = msg; 1138 } 1139 1140 /** 1141 * Set a listener to be invoked when the dialog is dismissed. 1142 * @param listener The {@link DialogInterface.OnDismissListener} to use. 1143 */ 1144 public void setOnDismissListener(final OnDismissListener listener) { 1145 if (mCancelAndDismissTaken != null) { 1146 throw new IllegalStateException( 1147 "OnDismissListener is already taken by " 1148 + mCancelAndDismissTaken + " and can not be replaced."); 1149 } 1150 if (listener != null) { 1151 mDismissMessage = mListenersHandler.obtainMessage(DISMISS, listener); 1152 } else { 1153 mDismissMessage = null; 1154 } 1155 } 1156 1157 /** 1158 * Sets a listener to be invoked when the dialog is shown. 1159 * @param listener The {@link DialogInterface.OnShowListener} to use. 1160 */ 1161 public void setOnShowListener(OnShowListener listener) { 1162 if (listener != null) { 1163 mShowMessage = mListenersHandler.obtainMessage(SHOW, listener); 1164 } else { 1165 mShowMessage = null; 1166 } 1167 } 1168 1169 /** 1170 * Set a message to be sent when the dialog is dismissed. 1171 * @param msg The msg to send when the dialog is dismissed. 1172 */ 1173 public void setDismissMessage(final Message msg) { 1174 mDismissMessage = msg; 1175 } 1176 1177 /** @hide */ 1178 public boolean takeCancelAndDismissListeners(String msg, final OnCancelListener cancel, 1179 final OnDismissListener dismiss) { 1180 if (mCancelAndDismissTaken != null) { 1181 mCancelAndDismissTaken = null; 1182 } else if (mCancelMessage != null || mDismissMessage != null) { 1183 return false; 1184 } 1185 1186 setOnCancelListener(cancel); 1187 setOnDismissListener(dismiss); 1188 mCancelAndDismissTaken = msg; 1189 1190 return true; 1191 } 1192 1193 /** 1194 * By default, this will use the owner Activity's suggested stream type. 1195 * 1196 * @see Activity#setVolumeControlStream(int) 1197 * @see #setOwnerActivity(Activity) 1198 */ 1199 public final void setVolumeControlStream(int streamType) { 1200 getWindow().setVolumeControlStream(streamType); 1201 } 1202 1203 /** 1204 * @see Activity#getVolumeControlStream() 1205 */ 1206 public final int getVolumeControlStream() { 1207 return getWindow().getVolumeControlStream(); 1208 } 1209 1210 /** 1211 * Sets the callback that will be called if a key is dispatched to the dialog. 1212 */ 1213 public void setOnKeyListener(final OnKeyListener onKeyListener) { 1214 mOnKeyListener = onKeyListener; 1215 } 1216 1217 private static final class ListenersHandler extends Handler { 1218 private WeakReference<DialogInterface> mDialog; 1219 1220 public ListenersHandler(Dialog dialog) { 1221 mDialog = new WeakReference<DialogInterface>(dialog); 1222 } 1223 1224 @Override 1225 public void handleMessage(Message msg) { 1226 switch (msg.what) { 1227 case DISMISS: 1228 ((OnDismissListener) msg.obj).onDismiss(mDialog.get()); 1229 break; 1230 case CANCEL: 1231 ((OnCancelListener) msg.obj).onCancel(mDialog.get()); 1232 break; 1233 case SHOW: 1234 ((OnShowListener) msg.obj).onShow(mDialog.get()); 1235 break; 1236 } 1237 } 1238 } 1239} 1240