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