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