1 /*
2  * Copyright (C) 2019 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 package com.android.internal.app.chooser;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.app.Activity;
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.pm.ActivityInfo;
26 import android.content.pm.ApplicationInfo;
27 import android.content.pm.ResolveInfo;
28 import android.graphics.drawable.Drawable;
29 import android.os.Bundle;
30 import android.os.Parcel;
31 import android.os.Parcelable;
32 import android.os.UserHandle;
33 
34 import com.android.internal.app.ResolverActivity;
35 import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter;
36 
37 import java.util.ArrayList;
38 import java.util.List;
39 
40 /**
41  * A TargetInfo plus additional information needed to render it (such as icon and label) and
42  * resolve it to an activity.
43  */
44 public class DisplayResolveInfo implements TargetInfo, Parcelable {
45     private final ResolveInfo mResolveInfo;
46     private CharSequence mDisplayLabel;
47     private Drawable mDisplayIcon;
48     private CharSequence mExtendedInfo;
49     private final Intent mResolvedIntent;
50     private final List<Intent> mSourceIntents = new ArrayList<>();
51     private boolean mIsSuspended;
52     private ResolveInfoPresentationGetter mResolveInfoPresentationGetter;
53     private boolean mPinned = false;
54 
DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, Intent pOrigIntent, ResolveInfoPresentationGetter resolveInfoPresentationGetter)55     public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, Intent pOrigIntent,
56             ResolveInfoPresentationGetter resolveInfoPresentationGetter) {
57         this(originalIntent, pri, null /*mDisplayLabel*/, null /*mExtendedInfo*/, pOrigIntent,
58                 resolveInfoPresentationGetter);
59     }
60 
DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel, CharSequence pInfo, @NonNull Intent resolvedIntent, @Nullable ResolveInfoPresentationGetter resolveInfoPresentationGetter)61     public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel,
62             CharSequence pInfo, @NonNull Intent resolvedIntent,
63             @Nullable ResolveInfoPresentationGetter resolveInfoPresentationGetter) {
64         mSourceIntents.add(originalIntent);
65         mResolveInfo = pri;
66         mDisplayLabel = pLabel;
67         mExtendedInfo = pInfo;
68         mResolveInfoPresentationGetter = resolveInfoPresentationGetter;
69 
70         final Intent intent = new Intent(resolvedIntent);
71         intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
72                 | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
73         final ActivityInfo ai = mResolveInfo.activityInfo;
74         intent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name));
75 
76         mIsSuspended = (ai.applicationInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
77 
78         mResolvedIntent = intent;
79     }
80 
DisplayResolveInfo(DisplayResolveInfo other, Intent fillInIntent, int flags, ResolveInfoPresentationGetter resolveInfoPresentationGetter)81     private DisplayResolveInfo(DisplayResolveInfo other, Intent fillInIntent, int flags,
82             ResolveInfoPresentationGetter resolveInfoPresentationGetter) {
83         mSourceIntents.addAll(other.getAllSourceIntents());
84         mResolveInfo = other.mResolveInfo;
85         mDisplayLabel = other.mDisplayLabel;
86         mDisplayIcon = other.mDisplayIcon;
87         mExtendedInfo = other.mExtendedInfo;
88         mResolvedIntent = new Intent(other.mResolvedIntent);
89         mResolvedIntent.fillIn(fillInIntent, flags);
90         mResolveInfoPresentationGetter = resolveInfoPresentationGetter;
91     }
92 
DisplayResolveInfo(DisplayResolveInfo other)93     DisplayResolveInfo(DisplayResolveInfo other) {
94         mSourceIntents.addAll(other.getAllSourceIntents());
95         mResolveInfo = other.mResolveInfo;
96         mDisplayLabel = other.mDisplayLabel;
97         mDisplayIcon = other.mDisplayIcon;
98         mExtendedInfo = other.mExtendedInfo;
99         mResolvedIntent = other.mResolvedIntent;
100         mResolveInfoPresentationGetter = other.mResolveInfoPresentationGetter;
101     }
102 
getResolveInfo()103     public ResolveInfo getResolveInfo() {
104         return mResolveInfo;
105     }
106 
getDisplayLabel()107     public CharSequence getDisplayLabel() {
108         if (mDisplayLabel == null && mResolveInfoPresentationGetter != null) {
109             mDisplayLabel = mResolveInfoPresentationGetter.getLabel();
110             mExtendedInfo = mResolveInfoPresentationGetter.getSubLabel();
111         }
112         return mDisplayLabel;
113     }
114 
hasDisplayLabel()115     public boolean hasDisplayLabel() {
116         return mDisplayLabel != null;
117     }
118 
setDisplayLabel(CharSequence displayLabel)119     public void setDisplayLabel(CharSequence displayLabel) {
120         mDisplayLabel = displayLabel;
121     }
122 
setExtendedInfo(CharSequence extendedInfo)123     public void setExtendedInfo(CharSequence extendedInfo) {
124         mExtendedInfo = extendedInfo;
125     }
126 
getDisplayIcon(Context context)127     public Drawable getDisplayIcon(Context context) {
128         return mDisplayIcon;
129     }
130 
131     @Override
cloneFilledIn(Intent fillInIntent, int flags)132     public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
133         return new DisplayResolveInfo(this, fillInIntent, flags, mResolveInfoPresentationGetter);
134     }
135 
136     @Override
getAllSourceIntents()137     public List<Intent> getAllSourceIntents() {
138         return mSourceIntents;
139     }
140 
addAlternateSourceIntent(Intent alt)141     public void addAlternateSourceIntent(Intent alt) {
142         mSourceIntents.add(alt);
143     }
144 
setDisplayIcon(Drawable icon)145     public void setDisplayIcon(Drawable icon) {
146         mDisplayIcon = icon;
147     }
148 
hasDisplayIcon()149     public boolean hasDisplayIcon() {
150         return mDisplayIcon != null;
151     }
152 
getExtendedInfo()153     public CharSequence getExtendedInfo() {
154         return mExtendedInfo;
155     }
156 
getResolvedIntent()157     public Intent getResolvedIntent() {
158         return mResolvedIntent;
159     }
160 
161     @Override
getResolvedComponentName()162     public ComponentName getResolvedComponentName() {
163         return new ComponentName(mResolveInfo.activityInfo.packageName,
164                 mResolveInfo.activityInfo.name);
165     }
166 
167     @Override
start(Activity activity, Bundle options)168     public boolean start(Activity activity, Bundle options) {
169         activity.startActivity(mResolvedIntent, options);
170         return true;
171     }
172 
173     @Override
startAsCaller(ResolverActivity activity, Bundle options, int userId)174     public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
175         TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, userId);
176         activity.startActivityAsCaller(mResolvedIntent, options, false, userId);
177         return true;
178     }
179 
180     @Override
startAsUser(Activity activity, Bundle options, UserHandle user)181     public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
182         TargetInfo.prepareIntentForCrossProfileLaunch(mResolvedIntent, user.getIdentifier());
183         activity.startActivityAsUser(mResolvedIntent, options, user);
184         return false;
185     }
186 
isSuspended()187     public boolean isSuspended() {
188         return mIsSuspended;
189     }
190 
191     @Override
isPinned()192     public boolean isPinned() {
193         return mPinned;
194     }
195 
setPinned(boolean pinned)196     public void setPinned(boolean pinned) {
197         mPinned = pinned;
198     }
199 
200     @Override
describeContents()201     public int describeContents() {
202         return 0;
203     }
204 
205     @Override
writeToParcel(Parcel dest, int flags)206     public void writeToParcel(Parcel dest, int flags) {
207         dest.writeCharSequence(mDisplayLabel);
208         dest.writeCharSequence(mExtendedInfo);
209         dest.writeParcelable(mResolvedIntent, 0);
210         dest.writeTypedList(mSourceIntents);
211         dest.writeBoolean(mIsSuspended);
212         dest.writeBoolean(mPinned);
213         dest.writeParcelable(mResolveInfo, 0);
214     }
215 
216     public static final Parcelable.Creator<DisplayResolveInfo> CREATOR =
217             new Parcelable.Creator<DisplayResolveInfo>() {
218         public DisplayResolveInfo createFromParcel(Parcel in) {
219             return new DisplayResolveInfo(in);
220         }
221 
222         public DisplayResolveInfo[] newArray(int size) {
223             return new DisplayResolveInfo[size];
224         }
225     };
226 
DisplayResolveInfo(Parcel in)227     private DisplayResolveInfo(Parcel in) {
228         mDisplayLabel = in.readCharSequence();
229         mExtendedInfo = in.readCharSequence();
230         mResolvedIntent = in.readParcelable(null /* ClassLoader */, android.content.Intent.class);
231         in.readTypedList(mSourceIntents, Intent.CREATOR);
232         mIsSuspended = in.readBoolean();
233         mPinned = in.readBoolean();
234         mResolveInfo = in.readParcelable(null /* ClassLoader */, android.content.pm.ResolveInfo.class);
235     }
236 }
237