1 /* 2 * Copyright (C) 2016 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 package androidx.wear.ble.view; 17 18 import android.app.AlertDialog; 19 import android.content.Context; 20 import android.content.DialogInterface; 21 import android.content.res.Resources; 22 import android.graphics.drawable.Drawable; 23 import androidx.annotation.DrawableRes; 24 import androidx.annotation.NonNull; 25 import androidx.annotation.Nullable; 26 import androidx.annotation.VisibleForTesting; 27 import android.util.Log; 28 import android.widget.Button; 29 30 /** 31 * Helper to add icons to AlertDialog buttons.AlertDialog buttons. 32 */ 33 public class WearableDialogHelper { 34 private static final String TAG = "WearableDialogHelper"; 35 36 private int mPositiveIconId; 37 private Drawable mPositiveIcon; 38 39 private int mNeutralIconId; 40 private Drawable mNeutralIcon; 41 42 private int mNegativeIconId; 43 private Drawable mNegativeIcon; 44 45 @VisibleForTesting /* package */ Resources mResources; 46 @VisibleForTesting /* package */ Resources.Theme mTheme; 47 48 /** 49 * Convenience constructor, equivalent to {@code new WearableDialogHelper(context.getResources(), 50 * context.getTheme())}. 51 */ WearableDialogHelper(@onNull Context context)52 public WearableDialogHelper(@NonNull Context context) { 53 this(context.getResources(), context.getTheme()); 54 } 55 56 /** 57 * @param resources the Resources used to obtain Drawables from resource IDs. 58 * @param theme the Theme used to properly obtain Drawables from resource IDs. 59 */ WearableDialogHelper(@onNull Resources resources, @NonNull Resources.Theme theme)60 public WearableDialogHelper(@NonNull Resources resources, @NonNull Resources.Theme theme) { 61 mResources = resources; 62 mTheme = theme; 63 } 64 65 @Nullable getPositiveIcon()66 public Drawable getPositiveIcon() { 67 return resolveDrawable(mPositiveIcon, mPositiveIconId); 68 } 69 70 @Nullable getNegativeIcon()71 public Drawable getNegativeIcon() { 72 return resolveDrawable(mNegativeIcon, mNegativeIconId); 73 } 74 75 @Nullable getNeutralIcon()76 public Drawable getNeutralIcon() { 77 return resolveDrawable(mNeutralIcon, mNeutralIconId); 78 } 79 80 @NonNull setPositiveIcon(@rawableRes int resId)81 public WearableDialogHelper setPositiveIcon(@DrawableRes int resId) { 82 mPositiveIconId = resId; 83 mPositiveIcon = null; 84 return this; 85 } 86 87 @NonNull setPositiveIcon(@ullable Drawable icon)88 public WearableDialogHelper setPositiveIcon(@Nullable Drawable icon) { 89 mPositiveIcon = icon; 90 mPositiveIconId = 0; 91 return this; 92 } 93 94 @NonNull setNegativeIcon(@rawableRes int resId)95 public WearableDialogHelper setNegativeIcon(@DrawableRes int resId) { 96 mNegativeIconId = resId; 97 mNegativeIcon = null; 98 return this; 99 } 100 101 @NonNull setNegativeIcon(@ullable Drawable icon)102 public WearableDialogHelper setNegativeIcon(@Nullable Drawable icon) { 103 mNegativeIcon = icon; 104 mNegativeIconId = 0; 105 return this; 106 } 107 108 @NonNull setNeutralIcon(@rawableRes int resId)109 public WearableDialogHelper setNeutralIcon(@DrawableRes int resId) { 110 mNeutralIconId = resId; 111 mNeutralIcon = null; 112 return this; 113 } 114 115 @NonNull setNeutralIcon(@ullable Drawable icon)116 public WearableDialogHelper setNeutralIcon(@Nullable Drawable icon) { 117 mNeutralIcon = icon; 118 mNeutralIconId = 0; 119 return this; 120 } 121 122 /** 123 * Applies the button icons setup in the helper to the buttons in the dialog. 124 * 125 * <p>Note that this should be called after {@code AlertDialog.create()}, NOT {@code 126 * AlertDialog.Builder.create()}. Calling {@code AlertDialog.Builder.show()} would also accomplish 127 * the same thing. 128 * 129 * @param dialog the AlertDialog to style with the helper. 130 */ apply(@onNull AlertDialog dialog)131 public void apply(@NonNull AlertDialog dialog) { 132 applyButton(dialog.getButton(DialogInterface.BUTTON_POSITIVE), getPositiveIcon()); 133 applyButton(dialog.getButton(DialogInterface.BUTTON_NEGATIVE), getNegativeIcon()); 134 applyButton(dialog.getButton(DialogInterface.BUTTON_NEUTRAL), getNeutralIcon()); 135 } 136 137 /** Applies the specified drawable to the button. */ 138 @VisibleForTesting applyButton(@ullable Button button, @Nullable Drawable drawable)139 /* package */ void applyButton(@Nullable Button button, @Nullable Drawable drawable) { 140 if (button != null) { 141 button.setCompoundDrawablesRelativeWithIntrinsicBounds(drawable, null, null, null); 142 button.setAllCaps(false); 143 } else if (drawable != null) { 144 Log.w(TAG, "non-null drawable used with missing button, did you call AlertDialog.create()?"); 145 } 146 } 147 148 /** Obtain a drawable between a drawable and a resource ID. */ 149 @VisibleForTesting resolveDrawable(@ullable Drawable drawable, @DrawableRes int resId)150 /* package */ Drawable resolveDrawable(@Nullable Drawable drawable, @DrawableRes int resId) { 151 return drawable == null && resId != 0 ? mResources.getDrawable(resId, mTheme) : drawable; 152 } 153 154 /** Convenience builder to generate an AlertDialog with icons in buttons. */ 155 public static class DialogBuilder extends AlertDialog.Builder { 156 private final WearableDialogHelper mHelper; 157 DialogBuilder(Context context)158 public DialogBuilder(Context context) { 159 super(context); 160 mHelper = new WearableDialogHelper(context.getResources(), context.getTheme()); 161 } 162 DialogBuilder(Context context, int themeResId)163 public DialogBuilder(Context context, int themeResId) { 164 super(context, themeResId); 165 mHelper = new WearableDialogHelper(context.getResources(), context.getTheme()); 166 } 167 getHelper()168 public WearableDialogHelper getHelper() { 169 return mHelper; 170 } 171 setPositiveIcon(@rawableRes int iconId)172 public DialogBuilder setPositiveIcon(@DrawableRes int iconId) { 173 mHelper.setPositiveIcon(iconId); 174 return this; 175 } 176 setPositiveIcon(@ullable Drawable icon)177 public DialogBuilder setPositiveIcon(@Nullable Drawable icon) { 178 mHelper.setPositiveIcon(icon); 179 return this; 180 } 181 setNegativeIcon(@rawableRes int iconId)182 public DialogBuilder setNegativeIcon(@DrawableRes int iconId) { 183 mHelper.setNegativeIcon(iconId); 184 return this; 185 } 186 setNegativeIcon(@ullable Drawable icon)187 public DialogBuilder setNegativeIcon(@Nullable Drawable icon) { 188 mHelper.setNegativeIcon(icon); 189 return this; 190 } 191 setNeutralIcon(@rawableRes int iconId)192 public DialogBuilder setNeutralIcon(@DrawableRes int iconId) { 193 mHelper.setNeutralIcon(iconId); 194 return this; 195 } 196 setNeutralIcon(@ullable Drawable icon)197 public DialogBuilder setNeutralIcon(@Nullable Drawable icon) { 198 mHelper.setNeutralIcon(icon); 199 return this; 200 } 201 202 @Override create()203 public AlertDialog create() { 204 final AlertDialog dialog = super.create(); 205 dialog.create(); 206 mHelper.apply(dialog); 207 return dialog; 208 } 209 210 @Override show()211 public AlertDialog show() { 212 final AlertDialog dialog = this.create(); 213 dialog.show(); 214 return dialog; 215 } 216 } 217 } 218