ChooserTarget.java revision 13036beab1579fabe1a93e1839c13cb68a49adf6
1/*
2 * Copyright (C) 2015 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
17
18package android.service.chooser;
19
20import android.app.Activity;
21import android.app.PendingIntent;
22import android.content.ComponentName;
23import android.content.Context;
24import android.content.Intent;
25import android.content.IntentFilter;
26import android.content.IntentSender;
27import android.graphics.Bitmap;
28import android.graphics.drawable.Icon;
29import android.os.Bundle;
30import android.os.Parcel;
31import android.os.Parcelable;
32import android.os.UserHandle;
33import android.util.Log;
34
35/**
36 * A ChooserTarget represents a deep-link into an application as returned by a
37 * {@link android.service.chooser.ChooserTargetService}.
38 *
39 * <p>A chooser target represents a specific deep link target into an application exposed
40 * for selection by the user. This might be a frequently emailed contact, a recently active
41 * group messaging conversation, a folder in a cloud storage app, a collection of related
42 * items published on a social media service or any other contextually relevant grouping
43 * of target app + relevant metadata.</p>
44 *
45 * <p>Creators of chooser targets should consult the relevant design guidelines for the type
46 * of target they are presenting. For example, targets involving people should be presented
47 * with a circular icon.</p>
48 */
49public final class ChooserTarget implements Parcelable {
50    private static final String TAG = "ChooserTarget";
51
52    /**
53     * The title of this target that will be shown to the user. The title may be truncated
54     * if it is too long to display in the space provided.
55     */
56    private CharSequence mTitle;
57
58    /**
59     * The icon that will be shown to the user to represent this target.
60     * The system may resize this icon as appropriate.
61     */
62    private Icon mIcon;
63
64    /**
65     * The IntentSender that will be used to deliver the intent to the target.
66     * It will be {@link android.content.Intent#fillIn(android.content.Intent, int)} filled in}
67     * by the real intent sent by the application.
68     */
69    private IntentSender mIntentSender;
70
71    /**
72     * The score given to this item. It can be normalized.
73     */
74    private float mScore;
75
76    /**
77     * Construct a deep link target for presentation by a chooser UI.
78     *
79     * <p>A target is composed of a title and an icon for presentation to the user.
80     * The UI presenting this target may truncate the title if it is too long to be presented
81     * in the available space, as well as crop, resize or overlay the supplied icon.</p>
82     *
83     * <p>The creator of a target may supply a ranking score. This score is assumed to be relative
84     * to the other targets supplied by the same
85     * {@link ChooserTargetService#onGetChooserTargets(ComponentName, IntentFilter) query}.
86     * Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match).
87     * Scores for a set of targets do not need to sum to 1.</p>
88     *
89     * <p>Before being sent, the PendingIntent supplied will be
90     * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
91     * to the chooser. When constructing a PendingIntent for use in a ChooserTarget, make sure
92     * that you permit the relevant fields to be filled in using the appropriate flags such as
93     * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES},
94     * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that
95     * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants
96     * for {@link Intent#ACTION_SEND} intents.</p>
97     *
98     * <p>Take care not to place custom {@link android.os.Parcelable} types into
99     * the PendingIntent as extras, as the system will not be able to unparcel it to merge
100     * additional extras.</p>
101     *
102     * @param title title of this target that will be shown to a user
103     * @param icon icon to represent this target
104     * @param score ranking score for this target between 0.0f and 1.0f, inclusive
105     * @param pendingIntent PendingIntent to fill in and send if the user chooses this target
106     */
107    public ChooserTarget(CharSequence title, Icon icon, float score,
108            PendingIntent pendingIntent) {
109        this(title, icon, score, pendingIntent.getIntentSender());
110    }
111
112    /**
113     * Construct a deep link target for presentation by a chooser UI.
114     *
115     * <p>A target is composed of a title and an icon for presentation to the user.
116     * The UI presenting this target may truncate the title if it is too long to be presented
117     * in the available space, as well as crop, resize or overlay the supplied icon.</p>
118     *
119     * <p>The creator of a target may supply a ranking score. This score is assumed to be relative
120     * to the other targets supplied by the same
121     * {@link ChooserTargetService#onGetChooserTargets(ComponentName, IntentFilter) query}.
122     * Scores should be in the range from 0.0f (unlikely match) to 1.0f (very relevant match).
123     * Scores for a set of targets do not need to sum to 1.</p>
124     *
125     * <p>Before being sent, the IntentSender supplied will be
126     * {@link Intent#fillIn(Intent, int) filled in} by the Intent originally supplied
127     * to the chooser. When constructing an IntentSender for use in a ChooserTarget, make sure
128     * that you permit the relevant fields to be filled in using the appropriate flags such as
129     * {@link Intent#FILL_IN_ACTION}, {@link Intent#FILL_IN_CATEGORIES},
130     * {@link Intent#FILL_IN_DATA} and {@link Intent#FILL_IN_CLIP_DATA}. Note that
131     * {@link Intent#FILL_IN_CLIP_DATA} is required to appropriately receive URI permission grants
132     * for {@link Intent#ACTION_SEND} intents.</p>
133     *
134     * <p>Take care not to place custom {@link android.os.Parcelable} types into
135     * the IntentSender as extras, as the system will not be able to unparcel it to merge
136     * additional extras.</p>
137     *
138     * @param title title of this target that will be shown to a user
139     * @param icon icon to represent this target
140     * @param score ranking score for this target between 0.0f and 1.0f, inclusive
141     * @param intentSender IntentSender to fill in and send if the user chooses this target
142     */
143    public ChooserTarget(CharSequence title, Icon icon, float score, IntentSender intentSender) {
144        mTitle = title;
145        mIcon = icon;
146        if (score > 1.f || score < 0.f) {
147            throw new IllegalArgumentException("Score " + score + " out of range; "
148                    + "must be between 0.0f and 1.0f");
149        }
150        mScore = score;
151        mIntentSender = intentSender;
152    }
153
154    ChooserTarget(Parcel in) {
155        mTitle = in.readCharSequence();
156        if (in.readInt() != 0) {
157            mIcon = Icon.CREATOR.createFromParcel(in);
158        } else {
159            mIcon = null;
160        }
161        mScore = in.readFloat();
162        mIntentSender = IntentSender.readIntentSenderOrNullFromParcel(in);
163    }
164
165    /**
166     * Returns the title of this target for display to a user. The UI displaying the title
167     * may truncate this title if it is too long to be displayed in full.
168     *
169     * @return the title of this target, intended to be shown to a user
170     */
171    public CharSequence getTitle() {
172        return mTitle;
173    }
174
175    /**
176     * Returns the icon representing this target for display to a user. The UI displaying the icon
177     * may crop, resize or overlay this icon.
178     *
179     * @return the icon representing this target, intended to be shown to a user
180     */
181    public Icon getIcon() {
182        return mIcon;
183    }
184
185    /**
186     * Returns the ranking score supplied by the creator of this ChooserTarget.
187     * Values are between 0.0f and 1.0f. The UI displaying the target may
188     * take this score into account when sorting and merging targets from multiple sources.
189     *
190     * @return the ranking score for this target between 0.0f and 1.0f, inclusive
191     */
192    public float getScore() {
193        return mScore;
194    }
195
196    /**
197     * Returns the raw IntentSender supplied by the ChooserTarget's creator.
198     * This may be null if the creator specified a regular Intent instead.
199     *
200     * <p>To fill in and send the intent, see {@link #sendIntent(Context, Intent)}.</p>
201     *
202     * @return the IntentSender supplied by the ChooserTarget's creator
203     */
204    public IntentSender getIntentSender() {
205        return mIntentSender;
206    }
207
208    /**
209     * Fill in the IntentSender supplied by the ChooserTarget's creator and send it.
210     *
211     * @param context the sending Context; generally the Activity presenting the chooser UI
212     * @param fillInIntent the Intent provided to the Chooser to be sent to a selected target
213     * @return true if sending the Intent was successful
214     */
215    public boolean sendIntent(Context context, Intent fillInIntent) {
216        if (fillInIntent != null) {
217            fillInIntent.migrateExtraStreamToClipData();
218            fillInIntent.prepareToLeaveProcess();
219        }
220        if (mIntentSender != null) {
221            try {
222                mIntentSender.sendIntent(context, 0, fillInIntent, null, null);
223                return true;
224            } catch (IntentSender.SendIntentException e) {
225                Log.e(TAG, "sendIntent " + this + " failed", e);
226                return false;
227            }
228        } else {
229            Log.e(TAG, "sendIntent " + this + " failed - no IntentSender to send");
230            return false;
231        }
232    }
233
234    @Override
235    public String toString() {
236        return "ChooserTarget{"
237                + (mIntentSender != null ? mIntentSender.getCreatorPackage() : null)
238                + ", "
239                + "'" + mTitle
240                + "', " + mScore + "}";
241    }
242
243    @Override
244    public int describeContents() {
245        return 0;
246    }
247
248    @Override
249    public void writeToParcel(Parcel dest, int flags) {
250        dest.writeCharSequence(mTitle);
251        if (mIcon != null) {
252            dest.writeInt(1);
253            mIcon.writeToParcel(dest, 0);
254        } else {
255            dest.writeInt(0);
256        }
257        dest.writeFloat(mScore);
258        IntentSender.writeIntentSenderOrNullToParcel(mIntentSender, dest);
259    }
260
261    public static final Creator<ChooserTarget> CREATOR
262            = new Creator<ChooserTarget>() {
263        @Override
264        public ChooserTarget createFromParcel(Parcel source) {
265            return new ChooserTarget(source);
266        }
267
268        @Override
269        public ChooserTarget[] newArray(int size) {
270            return new ChooserTarget[size];
271        }
272    };
273}
274