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 */
16package android.support.wearable.view;
17
18import android.app.AlertDialog;
19import android.content.Context;
20import android.content.DialogInterface;
21import android.content.res.Resources;
22import android.graphics.drawable.Drawable;
23import android.support.annotation.DrawableRes;
24import android.support.annotation.NonNull;
25import android.support.annotation.Nullable;
26import android.support.annotation.VisibleForTesting;
27import android.util.Log;
28import android.widget.Button;
29
30/**
31 * Helper to add icons to AlertDialog buttons.AlertDialog buttons.
32 */
33public 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     */
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     */
60    public WearableDialogHelper(@NonNull Resources resources, @NonNull Resources.Theme theme) {
61        mResources = resources;
62        mTheme = theme;
63    }
64
65    @Nullable
66    public Drawable getPositiveIcon() {
67        return resolveDrawable(mPositiveIcon, mPositiveIconId);
68    }
69
70    @Nullable
71    public Drawable getNegativeIcon() {
72        return resolveDrawable(mNegativeIcon, mNegativeIconId);
73    }
74
75    @Nullable
76    public Drawable getNeutralIcon() {
77        return resolveDrawable(mNeutralIcon, mNeutralIconId);
78    }
79
80    @NonNull
81    public WearableDialogHelper setPositiveIcon(@DrawableRes int resId) {
82        mPositiveIconId = resId;
83        mPositiveIcon = null;
84        return this;
85    }
86
87    @NonNull
88    public WearableDialogHelper setPositiveIcon(@Nullable Drawable icon) {
89        mPositiveIcon = icon;
90        mPositiveIconId = 0;
91        return this;
92    }
93
94    @NonNull
95    public WearableDialogHelper setNegativeIcon(@DrawableRes int resId) {
96        mNegativeIconId = resId;
97        mNegativeIcon = null;
98        return this;
99    }
100
101    @NonNull
102    public WearableDialogHelper setNegativeIcon(@Nullable Drawable icon) {
103        mNegativeIcon = icon;
104        mNegativeIconId = 0;
105        return this;
106    }
107
108    @NonNull
109    public WearableDialogHelper setNeutralIcon(@DrawableRes int resId) {
110        mNeutralIconId = resId;
111        mNeutralIcon = null;
112        return this;
113    }
114
115    @NonNull
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     */
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
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
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
158        public DialogBuilder(Context context) {
159            super(context);
160            mHelper = new WearableDialogHelper(context.getResources(), context.getTheme());
161        }
162
163        public DialogBuilder(Context context, int themeResId) {
164            super(context, themeResId);
165            mHelper = new WearableDialogHelper(context.getResources(), context.getTheme());
166        }
167
168        public WearableDialogHelper getHelper() {
169            return mHelper;
170        }
171
172        public DialogBuilder setPositiveIcon(@DrawableRes int iconId) {
173            mHelper.setPositiveIcon(iconId);
174            return this;
175        }
176
177        public DialogBuilder setPositiveIcon(@Nullable Drawable icon) {
178            mHelper.setPositiveIcon(icon);
179            return this;
180        }
181
182        public DialogBuilder setNegativeIcon(@DrawableRes int iconId) {
183            mHelper.setNegativeIcon(iconId);
184            return this;
185        }
186
187        public DialogBuilder setNegativeIcon(@Nullable Drawable icon) {
188            mHelper.setNegativeIcon(icon);
189            return this;
190        }
191
192        public DialogBuilder setNeutralIcon(@DrawableRes int iconId) {
193            mHelper.setNeutralIcon(iconId);
194            return this;
195        }
196
197        public DialogBuilder setNeutralIcon(@Nullable Drawable icon) {
198            mHelper.setNeutralIcon(icon);
199            return this;
200        }
201
202        @Override
203        public AlertDialog create() {
204            final AlertDialog dialog = super.create();
205            dialog.create();
206            mHelper.apply(dialog);
207            return dialog;
208        }
209
210        @Override
211        public AlertDialog show() {
212            final AlertDialog dialog = this.create();
213            dialog.show();
214            return dialog;
215        }
216    }
217}
218