From ec186706df72fbb62bfe813d83cff9167dd95cb4 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Thu, 5 Dec 2013 11:10:31 -0800 Subject: [PATCH] Allow alert dialogs to inflate custom view layouts Adds APIs to set a layout resource ID as an AlertDialog's custom view. To make this useful for developers, also ensures that Dialog content is set up when calls are made to Dialog.findViewById() before show(). BUG: 11136748 Change-Id: I29747a28d7e30f4e31fe474424109ff29e1eaa98 --- api/current.txt | 1 + core/java/android/app/AlertDialog.java | 17 ++++++ core/java/android/app/Dialog.java | 15 +++-- .../android/internal/app/AlertController.java | 55 ++++++++++++++----- 4 files changed, 70 insertions(+), 18 deletions(-) diff --git a/api/current.txt b/api/current.txt index 0a88f87a8d216..0d1dc6a89c56d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3239,6 +3239,7 @@ package android.app { method public android.app.AlertDialog.Builder setSingleChoiceItems(android.widget.ListAdapter, int, android.content.DialogInterface.OnClickListener); method public android.app.AlertDialog.Builder setTitle(int); method public android.app.AlertDialog.Builder setTitle(java.lang.CharSequence); + method public android.app.AlertDialog.Builder setView(int); method public android.app.AlertDialog.Builder setView(android.view.View); method public android.app.AlertDialog show(); } diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java index 77526c3542dbf..2fd3cc8a49bf4 100644 --- a/core/java/android/app/AlertDialog.java +++ b/core/java/android/app/AlertDialog.java @@ -851,6 +851,21 @@ public class AlertDialog extends Dialog implements DialogInterface { return this; } + /** + * Set a custom view resource to be the contents of the Dialog. The + * resource will be inflated, adding all top-level views to the screen. + * + * @param layoutResId Resource ID to be inflated. + * @return This Builder object to allow for chaining of calls to set + * methods + */ + public Builder setView(int layoutResId) { + P.mView = null; + P.mViewLayoutResId = layoutResId; + P.mViewSpacingSpecified = false; + return this; + } + /** * Set a custom view to be the contents of the Dialog. If the supplied view is an instance * of a {@link ListView} the light background will be used. @@ -861,6 +876,7 @@ public class AlertDialog extends Dialog implements DialogInterface { */ public Builder setView(View view) { P.mView = view; + P.mViewLayoutResId = 0; P.mViewSpacingSpecified = false; return this; } @@ -890,6 +906,7 @@ public class AlertDialog extends Dialog implements DialogInterface { public Builder setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight, int viewSpacingBottom) { P.mView = view; + P.mViewLayoutResId = 0; P.mViewSpacingSpecified = true; P.mViewSpacingLeft = viewSpacingLeft; P.mViewSpacingTop = viewSpacingTop; diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index 92f3ffcfc9638..a041a46f8b919 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -456,13 +456,20 @@ public class Dialog implements DialogInterface, Window.Callback, } /** - * Finds a view that was identified by the id attribute from the XML that - * was processed in {@link #onStart}. + * Finds a child view with the given identifier. + *

+ * Prior to API 20, this function could only be used after the first call + * to {@link #show()}. In later versions, this function may be used at any + * time; however, the first call to this function "locks in" certain dialog + * characteristics. * * @param id the identifier of the view to find - * @return The view if found or null otherwise. + * @return The view with the given id or null. */ public View findViewById(int id) { + if (!mCreated) { + dispatchOnCreate(null); + } return mWindow.findViewById(id); } @@ -479,7 +486,7 @@ public class Dialog implements DialogInterface, Window.Callback, /** * Set the screen content to an explicit view. This view is placed * directly into the screen's view hierarchy. It can itself be a complex - * view hierarhcy. + * view hierarchy. * * @param view The desired content to display. */ diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java index 10b98d83ba003..a7a7e7ed2bf87 100644 --- a/core/java/com/android/internal/app/AlertController.java +++ b/core/java/com/android/internal/app/AlertController.java @@ -70,6 +70,8 @@ public class AlertController { private View mView; + private int mViewLayoutResId; + private int mViewSpacingLeft; private int mViewSpacingTop; @@ -232,11 +234,6 @@ public class AlertController { public void installContent() { /* We use a custom title so never request a window title */ mWindow.requestFeature(Window.FEATURE_NO_TITLE); - - if (mView == null || !canTextInput(mView)) { - mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - } mWindow.setContentView(mAlertDialogLayout); setupView(); } @@ -262,11 +259,21 @@ public class AlertController { } } + /** + * Set the view resource to display in the dialog. + */ + public void setView(int layoutResId) { + mView = null; + mViewLayoutResId = layoutResId; + mViewSpacingSpecified = false; + } + /** * Set the view to display in the dialog. */ public void setView(View view) { mView = view; + mViewLayoutResId = 0; mViewSpacingSpecified = false; } @@ -276,6 +283,7 @@ public class AlertController { public void setView(View view, int viewSpacingLeft, int viewSpacingTop, int viewSpacingRight, int viewSpacingBottom) { mView = view; + mViewLayoutResId = 0; mViewSpacingSpecified = true; mViewSpacingLeft = viewSpacingLeft; mViewSpacingTop = viewSpacingTop; @@ -406,20 +414,36 @@ public class AlertController { mWindow.setCloseOnTouchOutsideIfNotSet(true); } - FrameLayout customPanel = null; + final FrameLayout customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel); + final View customView; if (mView != null) { - customPanel = (FrameLayout) mWindow.findViewById(R.id.customPanel); - FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom); - custom.addView(mView, new LayoutParams(MATCH_PARENT, MATCH_PARENT)); + customView = mView; + } else if (mViewLayoutResId != 0) { + final LayoutInflater inflater = LayoutInflater.from(mContext); + customView = inflater.inflate(mViewLayoutResId, customPanel, false); + } else { + customView = null; + } + + if (customView == null || !canTextInput(customView)) { + mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, + WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); + } + + if (customView != null) { + final FrameLayout custom = (FrameLayout) mWindow.findViewById(R.id.custom); + custom.addView(customView, new LayoutParams(MATCH_PARENT, MATCH_PARENT)); + if (mViewSpacingSpecified) { - custom.setPadding(mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, - mViewSpacingBottom); + custom.setPadding( + mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, mViewSpacingBottom); } + if (mListView != null) { ((LinearLayout.LayoutParams) customPanel.getLayoutParams()).weight = 0; } } else { - mWindow.findViewById(R.id.customPanel).setVisibility(View.GONE); + customPanel.setVisibility(View.GONE); } /* Only display the divider if we have a title and a @@ -427,7 +451,7 @@ public class AlertController { */ if (hasTitle) { View divider = null; - if (mMessage != null || mView != null || mListView != null) { + if (mMessage != null || customView != null || mListView != null) { divider = mWindow.findViewById(R.id.titleDivider); } else { divider = mWindow.findViewById(R.id.titleDividerTop); @@ -774,6 +798,7 @@ public class AlertController { public CharSequence[] mItems; public ListAdapter mAdapter; public DialogInterface.OnClickListener mOnClickListener; + public int mViewLayoutResId; public View mView; public int mViewSpacingLeft; public int mViewSpacingTop; @@ -859,8 +884,10 @@ public class AlertController { } else { dialog.setView(mView); } + } else if (mViewLayoutResId != 0) { + dialog.setView(mViewLayoutResId); } - + /* dialog.setCancelable(mCancelable); dialog.setOnCancelListener(mOnCancelListener);