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