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