diff options
| -rw-r--r-- | api/current.txt | 5 | ||||
| -rw-r--r-- | core/java/android/app/Activity.java | 25 | ||||
| -rw-r--r-- | core/java/android/app/Dialog.java | 35 | ||||
| -rw-r--r-- | core/java/android/service/dreams/DreamService.java | 37 | ||||
| -rw-r--r-- | core/java/android/view/View.java | 25 | ||||
| -rw-r--r-- | core/java/android/view/Window.java | 30 |
6 files changed, 147 insertions, 10 deletions
diff --git a/api/current.txt b/api/current.txt index ebd3cfa3379c..f7cfc75dc41f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3764,6 +3764,7 @@ package android.app { method public final void requestShowKeyboardShortcuts(); method public deprecated boolean requestVisibleBehind(boolean); method public final boolean requestWindowFeature(int); + method public final <T extends android.view.View> T requireViewById(int); method public final void runOnUiThread(java.lang.Runnable); method public void setActionBar(android.widget.Toolbar); method public void setContentTransitionManager(android.transition.TransitionManager); @@ -4458,6 +4459,7 @@ package android.app { method public void openOptionsMenu(); method public void registerForContextMenu(android.view.View); method public final boolean requestWindowFeature(int); + method public final <T extends android.view.View> T requireViewById(int); method public void setCancelMessage(android.os.Message); method public void setCancelable(boolean); method public void setCanceledOnTouchOutside(boolean); @@ -38455,6 +38457,7 @@ package android.service.dreams { method public void onWindowFocusChanged(boolean); method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback); method public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int); + method public final <T extends android.view.View> T requireViewById(int); method public void setContentView(int); method public void setContentView(android.view.View); method public void setContentView(android.view.View, android.view.ViewGroup.LayoutParams); @@ -46942,6 +46945,7 @@ package android.view { method public boolean requestRectangleOnScreen(android.graphics.Rect); method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean); method public final void requestUnbufferedDispatch(android.view.MotionEvent); + method public final <T extends android.view.View> T requireViewById(int); method public static int resolveSize(int, int); method public static int resolveSizeAndState(int, int, int); method public boolean restoreDefaultFocus(); @@ -47977,6 +47981,7 @@ package android.view { method public abstract boolean performPanelShortcut(int, int, android.view.KeyEvent, int); method public final void removeOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener); method public boolean requestFeature(int); + method public final <T extends android.view.View> T requireViewById(int); method public abstract void restoreHierarchyState(android.os.Bundle); method public abstract android.os.Bundle saveHierarchyState(); method public void setAllowEnterTransitionOverlap(boolean); diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 73fbb1933943..cd029c06b91d 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2619,6 +2619,7 @@ public class Activity extends ContextThemeWrapper * @param id the ID to search for * @return a view with given ID if found, or {@code null} otherwise * @see View#findViewById(int) + * @see Activity#requireViewById(int) */ @Nullable public <T extends View> T findViewById(@IdRes int id) { @@ -2626,6 +2627,30 @@ public class Activity extends ContextThemeWrapper } /** + * Finds a view that was identified by the {@code android:id} XML attribute that was processed + * in {@link #onCreate}, or throws an IllegalArgumentException if the ID is invalid, or there is + * no matching view in the hierarchy. + * <p> + * <strong>Note:</strong> In most cases -- depending on compiler support -- + * the resulting view is automatically cast to the target class type. If + * the target class type is unconstrained, an explicit cast may be + * necessary. + * + * @param id the ID to search for + * @return a view with given ID + * @see View#requireViewById(int) + * @see Activity#findViewById(int) + */ + @NonNull + public final <T extends View> T requireViewById(@IdRes int id) { + T view = findViewById(id); + if (view == null) { + throw new IllegalArgumentException("ID does not reference a View inside this Activity"); + } + return view; + } + + /** * Retrieve a reference to this activity's ActionBar. * * @return The Activity's ActionBar, or null if it does not have one. diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java index b162cb165fba..2b648ea6937d 100644 --- a/core/java/android/app/Dialog.java +++ b/core/java/android/app/Dialog.java @@ -16,10 +16,6 @@ package android.app; -import com.android.internal.R; -import com.android.internal.app.WindowDecorActionBar; -import com.android.internal.policy.PhoneWindow; - import android.annotation.CallSuper; import android.annotation.DrawableRes; import android.annotation.IdRes; @@ -32,8 +28,8 @@ import android.content.ComponentName; import android.content.Context; import android.content.ContextWrapper; import android.content.DialogInterface; -import android.content.res.Configuration; import android.content.pm.ApplicationInfo; +import android.content.res.Configuration; import android.content.res.ResourceId; import android.graphics.drawable.Drawable; import android.net.Uri; @@ -62,6 +58,10 @@ import android.view.Window; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; +import com.android.internal.R; +import com.android.internal.app.WindowDecorActionBar; +import com.android.internal.policy.PhoneWindow; + import java.lang.ref.WeakReference; /** @@ -512,6 +512,7 @@ public class Dialog implements DialogInterface, Window.Callback, * @param id the ID to search for * @return a view with given ID if found, or {@code null} otherwise * @see View#findViewById(int) + * @see Dialog#requireViewById(int) */ @Nullable public <T extends View> T findViewById(@IdRes int id) { @@ -519,6 +520,30 @@ public class Dialog implements DialogInterface, Window.Callback, } /** + * Finds the first descendant view with the given ID or throws an IllegalArgumentException if + * the ID is invalid (< 0), there is no matching view in the hierarchy, or the dialog has not + * yet been fully created (for example, via {@link #show()} or {@link #create()}). + * <p> + * <strong>Note:</strong> In most cases -- depending on compiler support -- + * the resulting view is automatically cast to the target class type. If + * the target class type is unconstrained, an explicit cast may be + * necessary. + * + * @param id the ID to search for + * @return a view with given ID + * @see View#requireViewById(int) + * @see Dialog#findViewById(int) + */ + @NonNull + public final <T extends View> T requireViewById(@IdRes int id) { + T view = findViewById(id); + if (view == null) { + throw new IllegalArgumentException("ID does not reference a View inside this Dialog"); + } + return view; + } + + /** * Set the screen content from a layout resource. The resource will be * inflated, adding all top-level views to the screen. * diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 2a245d046486..99e2c620fa03 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -17,6 +17,7 @@ package android.service.dreams; import android.annotation.IdRes; import android.annotation.LayoutRes; +import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; @@ -54,7 +55,6 @@ import com.android.internal.util.DumpUtils.Dump; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.util.List; /** * Extend this class to implement a custom dream (available to the user as a "Daydream"). @@ -458,8 +458,16 @@ public class DreamService extends Service implements Window.Callback { * was processed in {@link #onCreate}. * * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> + * <p> + * <strong>Note:</strong> In most cases -- depending on compiler support -- + * the resulting view is automatically cast to the target class type. If + * the target class type is unconstrained, an explicit cast may be + * necessary. * + * @param id the ID to search for * @return The view if found or null otherwise. + * @see View#findViewById(int) + * @see DreamService#requireViewById(int) */ @Nullable public <T extends View> T findViewById(@IdRes int id) { @@ -467,6 +475,33 @@ public class DreamService extends Service implements Window.Callback { } /** + * Finds a view that was identified by the id attribute from the XML that was processed in + * {@link #onCreate}, or throws an IllegalArgumentException if the ID is invalid or there is no + * matching view in the hierarchy. + * + * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p> + * <p> + * <strong>Note:</strong> In most cases -- depending on compiler support -- + * the resulting view is automatically cast to the target class type. If + * the target class type is unconstrained, an explicit cast may be + * necessary. + * + * @param id the ID to search for + * @return a view with given ID + * @see View#requireViewById(int) + * @see DreamService#findViewById(int) + */ + @NonNull + public final <T extends View> T requireViewById(@IdRes int id) { + T view = findViewById(id); + if (view == null) { + throw new IllegalArgumentException( + "ID does not reference a View inside this DreamService"); + } + return view; + } + + /** * Marks this dream as interactive to receive input events. * * <p>Non-interactive dreams (default) will dismiss on the first input event.</p> diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 05770c357526..a2ecfc469182 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -22209,7 +22209,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * * @param id the ID to search for * @return a view with given ID if found, or {@code null} otherwise - * @see View#findViewById(int) + * @see View#requireViewById(int) */ @Nullable public final <T extends View> T findViewById(@IdRes int id) { @@ -22220,6 +22220,29 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Finds the first descendant view with the given ID, the view itself if the ID matches + * {@link #getId()}, or throws an IllegalArgumentException if the ID is invalid or there is no + * matching view in the hierarchy. + * <p> + * <strong>Note:</strong> In most cases -- depending on compiler support -- + * the resulting view is automatically cast to the target class type. If + * the target class type is unconstrained, an explicit cast may be + * necessary. + * + * @param id the ID to search for + * @return a view with given ID + * @see View#findViewById(int) + */ + @NonNull + public final <T extends View> T requireViewById(@IdRes int id) { + T view = findViewById(id); + if (view == null) { + throw new IllegalArgumentException("ID does not reference a View inside this View"); + } + return view; + } + + /** * Finds a view by its unuque and stable accessibility id. * * @param accessibilityId The searched accessibility id. diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 95abea14b1dd..5bd0782d6056 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -1339,9 +1339,9 @@ public abstract class Window { /** * Finds a view that was identified by the {@code android:id} XML attribute - * that was processed in {@link android.app.Activity#onCreate}. This will - * implicitly call {@link #getDecorView} with all of the associated - * side-effects. + * that was processed in {@link android.app.Activity#onCreate}. + * <p> + * This will implicitly call {@link #getDecorView} with all of the associated side-effects. * <p> * <strong>Note:</strong> In most cases -- depending on compiler support -- * the resulting view is automatically cast to the target class type. If @@ -1351,11 +1351,35 @@ public abstract class Window { * @param id the ID to search for * @return a view with given ID if found, or {@code null} otherwise * @see View#findViewById(int) + * @see Window#requireViewById(int) */ @Nullable public <T extends View> T findViewById(@IdRes int id) { return getDecorView().findViewById(id); } + /** + * Finds a view that was identified by the {@code android:id} XML attribute + * that was processed in {@link android.app.Activity#onCreate}, or throws an + * IllegalArgumentException if the ID is invalid, or there is no matching view in the hierarchy. + * <p> + * <strong>Note:</strong> In most cases -- depending on compiler support -- + * the resulting view is automatically cast to the target class type. If + * the target class type is unconstrained, an explicit cast may be + * necessary. + * + * @param id the ID to search for + * @return a view with given ID + * @see View#requireViewById(int) + * @see Window#findViewById(int) + */ + @NonNull + public final <T extends View> T requireViewById(@IdRes int id) { + T view = findViewById(id); + if (view == null) { + throw new IllegalArgumentException("ID does not reference a View inside this Window"); + } + return view; + } /** * Convenience for |