RemoteInput.java revision c39d9c75590eca86a5e7e32a8824ba04a0d42e9b
1/*
2 * Copyright (C) 2014 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
17package android.support.v4.app;
18
19import android.content.Intent;
20import android.os.Build;
21import android.os.Bundle;
22import android.support.annotation.RestrictTo;
23import android.util.Log;
24
25import static android.support.annotation.RestrictTo.Scope.GROUP_ID;
26
27/**
28 * Helper for using the {@link android.app.RemoteInput} API
29 * introduced after API level 4 in a backwards compatible fashion.
30 */
31public final class RemoteInput extends RemoteInputCompatBase.RemoteInput {
32    private static final String TAG = "RemoteInput";
33
34    /** Label used to denote the clip data type used for remote input transport */
35    public static final String RESULTS_CLIP_LABEL = RemoteInputCompatJellybean.RESULTS_CLIP_LABEL;
36
37    /** Extra added to a clip data intent object to hold the results bundle. */
38    public static final String EXTRA_RESULTS_DATA = RemoteInputCompatJellybean.EXTRA_RESULTS_DATA;
39
40    private final String mResultKey;
41    private final CharSequence mLabel;
42    private final CharSequence[] mChoices;
43    private final boolean mAllowFreeFormInput;
44    private final Bundle mExtras;
45
46    RemoteInput(String resultKey, CharSequence label, CharSequence[] choices,
47            boolean allowFreeFormInput, Bundle extras) {
48        this.mResultKey = resultKey;
49        this.mLabel = label;
50        this.mChoices = choices;
51        this.mAllowFreeFormInput = allowFreeFormInput;
52        this.mExtras = extras;
53    }
54
55    /**
56     * Get the key that the result of this input will be set in from the Bundle returned by
57     * {@link #getResultsFromIntent} when the {@link android.app.PendingIntent} is sent.
58     */
59    @Override
60    public String getResultKey() {
61        return mResultKey;
62    }
63
64    /**
65     * Get the label to display to users when collecting this input.
66     */
67    @Override
68    public CharSequence getLabel() {
69        return mLabel;
70    }
71
72    /**
73     * Get possible input choices. This can be {@code null} if there are no choices to present.
74     */
75    @Override
76    public CharSequence[] getChoices() {
77        return mChoices;
78    }
79
80    /**
81     * Get whether or not users can provide an arbitrary value for
82     * input. If you set this to {@code false}, users must select one of the
83     * choices in {@link #getChoices}. An {@link IllegalArgumentException} is thrown
84     * if you set this to false and {@link #getChoices} returns {@code null} or empty.
85     */
86    @Override
87    public boolean getAllowFreeFormInput() {
88        return mAllowFreeFormInput;
89    }
90
91    /**
92     * Get additional metadata carried around with this remote input.
93     */
94    @Override
95    public Bundle getExtras() {
96        return mExtras;
97    }
98
99    /**
100     * Builder class for {@link android.support.v4.app.RemoteInput} objects.
101     */
102    public static final class Builder {
103        private final String mResultKey;
104        private CharSequence mLabel;
105        private CharSequence[] mChoices;
106        private boolean mAllowFreeFormInput = true;
107        private Bundle mExtras = new Bundle();
108
109        /**
110         * Create a builder object for {@link android.support.v4.app.RemoteInput} objects.
111         * @param resultKey the Bundle key that refers to this input when collected from the user
112         */
113        public Builder(String resultKey) {
114            if (resultKey == null) {
115                throw new IllegalArgumentException("Result key can't be null");
116            }
117            mResultKey = resultKey;
118        }
119
120        /**
121         * Set a label to be displayed to the user when collecting this input.
122         * @param label The label to show to users when they input a response.
123         * @return this object for method chaining
124         */
125        public Builder setLabel(CharSequence label) {
126            mLabel = label;
127            return this;
128        }
129
130        /**
131         * Specifies choices available to the user to satisfy this input.
132         * @param choices an array of pre-defined choices for users input.
133         *        You must provide a non-null and non-empty array if
134         *        you disabled free form input using {@link #setAllowFreeFormInput}.
135         * @return this object for method chaining
136         */
137        public Builder setChoices(CharSequence[] choices) {
138            mChoices = choices;
139            return this;
140        }
141
142        /**
143         * Specifies whether the user can provide arbitrary values.
144         *
145         * @param allowFreeFormInput The default is {@code true}.
146         *         If you specify {@code false}, you must provide a non-null
147         *         and non-empty array to {@link #setChoices} or an
148         *         {@link IllegalArgumentException} is thrown.
149         * @return this object for method chaining
150         */
151        public Builder setAllowFreeFormInput(boolean allowFreeFormInput) {
152            mAllowFreeFormInput = allowFreeFormInput;
153            return this;
154        }
155
156        /**
157         * Merge additional metadata into this builder.
158         *
159         * <p>Values within the Bundle will replace existing extras values in this Builder.
160         *
161         * @see RemoteInput#getExtras
162         */
163        public Builder addExtras(Bundle extras) {
164            if (extras != null) {
165                mExtras.putAll(extras);
166            }
167            return this;
168        }
169
170        /**
171         * Get the metadata Bundle used by this Builder.
172         *
173         * <p>The returned Bundle is shared with this Builder.
174         */
175        public Bundle getExtras() {
176            return mExtras;
177        }
178
179        /**
180         * Combine all of the options that have been set and return a new
181         * {@link android.support.v4.app.RemoteInput} object.
182         */
183        public RemoteInput build() {
184            return new RemoteInput(mResultKey, mLabel, mChoices, mAllowFreeFormInput, mExtras);
185        }
186    }
187
188    /**
189     * Get the remote input results bundle from an intent. The returned Bundle will
190     * contain a key/value for every result key populated by remote input collector.
191     * Use the {@link Bundle#getCharSequence(String)} method to retrieve a value.
192     * @param intent The intent object that fired in response to an action or content intent
193     *               which also had one or more remote input requested.
194     */
195    public static Bundle getResultsFromIntent(Intent intent) {
196        return IMPL.getResultsFromIntent(intent);
197    }
198
199    /**
200     * Populate an intent object with the results gathered from remote input. This method
201     * should only be called by remote input collection services when sending results to a
202     * pending intent.
203     * @param remoteInputs The remote inputs for which results are being provided
204     * @param intent The intent to add remote inputs to. The {@link android.content.ClipData}
205     *               field of the intent will be modified to contain the results.
206     * @param results A bundle holding the remote input results. This bundle should
207     *                be populated with keys matching the result keys specified in
208     *                {@code remoteInputs} with values being the result per key.
209     */
210    public static void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent,
211            Bundle results) {
212        IMPL.addResultsToIntent(remoteInputs, intent, results);
213    }
214
215    private static final Impl IMPL;
216
217    interface Impl {
218        Bundle getResultsFromIntent(Intent intent);
219        void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent,
220                Bundle results);
221    }
222
223    static class ImplBase implements Impl {
224        @Override
225        public Bundle getResultsFromIntent(Intent intent) {
226            Log.w(TAG, "RemoteInput is only supported from API Level 16");
227            return null;
228        }
229
230        @Override
231        public void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent, Bundle results) {
232            Log.w(TAG, "RemoteInput is only supported from API Level 16");
233        }
234    }
235
236    static class ImplJellybean implements Impl {
237        @Override
238        public Bundle getResultsFromIntent(Intent intent) {
239            return RemoteInputCompatJellybean.getResultsFromIntent(intent);
240        }
241
242        @Override
243        public void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent, Bundle results) {
244            RemoteInputCompatJellybean.addResultsToIntent(remoteInputs, intent, results);
245        }
246    }
247
248    static class ImplApi20 implements Impl {
249        @Override
250        public Bundle getResultsFromIntent(Intent intent) {
251            return RemoteInputCompatApi20.getResultsFromIntent(intent);
252        }
253
254        @Override
255        public void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent, Bundle results) {
256            RemoteInputCompatApi20.addResultsToIntent(remoteInputs, intent, results);
257        }
258    }
259
260    static {
261        if (Build.VERSION.SDK_INT >= 20) {
262            IMPL = new ImplApi20();
263        } else if (Build.VERSION.SDK_INT >= 16) {
264            IMPL = new ImplJellybean();
265        } else {
266            IMPL = new ImplBase();
267        }
268    }
269
270    /** @hide */
271    @RestrictTo(GROUP_ID)
272    public static final Factory FACTORY = new Factory() {
273        @Override
274        public RemoteInput build(String resultKey,
275                CharSequence label, CharSequence[] choices, boolean allowFreeFormInput,
276                Bundle extras) {
277            return new RemoteInput(resultKey, label, choices, allowFreeFormInput, extras);
278        }
279
280        @Override
281        public RemoteInput[] newArray(int size) {
282            return new RemoteInput[size];
283        }
284    };
285}
286