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.UserHandle;
31 
32 import com.android.internal.app.ResolverActivity;
33 import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter;
34 
35 import java.util.ArrayList;
36 import java.util.List;
37 
38 /**
39  * A TargetInfo plus additional information needed to render it (such as icon and label) and
40  * resolve it to an activity.
41  */
42 public class DisplayResolveInfo implements TargetInfo {
43     // Temporary flag for new chooser delegate behavior. There are occassional token
44     // permission errors from bouncing through the delegate. Watch out before reenabling:
45     // b/157272342 is one example but this issue has been reported many times
46     private static final boolean ENABLE_CHOOSER_DELEGATE = false;
47 
48     private final ResolveInfo mResolveInfo;
49     private CharSequence mDisplayLabel;
50     private Drawable mDisplayIcon;
51     private CharSequence mExtendedInfo;
52     private final Intent mResolvedIntent;
53     private final List<Intent> mSourceIntents = new ArrayList<>();
54     private boolean mIsSuspended;
55     private ResolveInfoPresentationGetter mResolveInfoPresentationGetter;
56     private boolean mPinned = false;
57 
DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, Intent pOrigIntent, ResolveInfoPresentationGetter resolveInfoPresentationGetter)58     public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, Intent pOrigIntent,
59             ResolveInfoPresentationGetter resolveInfoPresentationGetter) {
60         this(originalIntent, pri, null /*mDisplayLabel*/, null /*mExtendedInfo*/, pOrigIntent,
61                 resolveInfoPresentationGetter);
62     }
63 
DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel, CharSequence pInfo, @NonNull Intent resolvedIntent, @Nullable ResolveInfoPresentationGetter resolveInfoPresentationGetter)64     public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel,
65             CharSequence pInfo, @NonNull Intent resolvedIntent,
66             @Nullable ResolveInfoPresentationGetter resolveInfoPresentationGetter) {
67         mSourceIntents.add(originalIntent);
68         mResolveInfo = pri;
69         mDisplayLabel = pLabel;
70         mExtendedInfo = pInfo;
71         mResolveInfoPresentationGetter = resolveInfoPresentationGetter;
72 
73         final Intent intent = new Intent(resolvedIntent);
74         intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
75                 | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
76         final ActivityInfo ai = mResolveInfo.activityInfo;
77         intent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name));
78 
79         mIsSuspended = (ai.applicationInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
80 
81         mResolvedIntent = intent;
82     }
83 
DisplayResolveInfo(DisplayResolveInfo other, Intent fillInIntent, int flags, ResolveInfoPresentationGetter resolveInfoPresentationGetter)84     private DisplayResolveInfo(DisplayResolveInfo other, Intent fillInIntent, int flags,
85             ResolveInfoPresentationGetter resolveInfoPresentationGetter) {
86         mSourceIntents.addAll(other.getAllSourceIntents());
87         mResolveInfo = other.mResolveInfo;
88         mDisplayLabel = other.mDisplayLabel;
89         mDisplayIcon = other.mDisplayIcon;
90         mExtendedInfo = other.mExtendedInfo;
91         mResolvedIntent = new Intent(other.mResolvedIntent);
92         mResolvedIntent.fillIn(fillInIntent, flags);
93         mResolveInfoPresentationGetter = resolveInfoPresentationGetter;
94     }
95 
DisplayResolveInfo(DisplayResolveInfo other)96     DisplayResolveInfo(DisplayResolveInfo other) {
97         mSourceIntents.addAll(other.getAllSourceIntents());
98         mResolveInfo = other.mResolveInfo;
99         mDisplayLabel = other.mDisplayLabel;
100         mDisplayIcon = other.mDisplayIcon;
101         mExtendedInfo = other.mExtendedInfo;
102         mResolvedIntent = other.mResolvedIntent;
103         mResolveInfoPresentationGetter = other.mResolveInfoPresentationGetter;
104     }
105 
getResolveInfo()106     public ResolveInfo getResolveInfo() {
107         return mResolveInfo;
108     }
109 
getDisplayLabel()110     public CharSequence getDisplayLabel() {
111         if (mDisplayLabel == null && mResolveInfoPresentationGetter != null) {
112             mDisplayLabel = mResolveInfoPresentationGetter.getLabel();
113             mExtendedInfo = mResolveInfoPresentationGetter.getSubLabel();
114         }
115         return mDisplayLabel;
116     }
117 
hasDisplayLabel()118     public boolean hasDisplayLabel() {
119         return mDisplayLabel != null;
120     }
121 
setDisplayLabel(CharSequence displayLabel)122     public void setDisplayLabel(CharSequence displayLabel) {
123         mDisplayLabel = displayLabel;
124     }
125 
setExtendedInfo(CharSequence extendedInfo)126     public void setExtendedInfo(CharSequence extendedInfo) {
127         mExtendedInfo = extendedInfo;
128     }
129 
getDisplayIcon(Context context)130     public Drawable getDisplayIcon(Context context) {
131         return mDisplayIcon;
132     }
133 
134     @Override
cloneFilledIn(Intent fillInIntent, int flags)135     public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
136         return new DisplayResolveInfo(this, fillInIntent, flags, mResolveInfoPresentationGetter);
137     }
138 
139     @Override
getAllSourceIntents()140     public List<Intent> getAllSourceIntents() {
141         return mSourceIntents;
142     }
143 
addAlternateSourceIntent(Intent alt)144     public void addAlternateSourceIntent(Intent alt) {
145         mSourceIntents.add(alt);
146     }
147 
setDisplayIcon(Drawable icon)148     public void setDisplayIcon(Drawable icon) {
149         mDisplayIcon = icon;
150     }
151 
hasDisplayIcon()152     public boolean hasDisplayIcon() {
153         return mDisplayIcon != null;
154     }
155 
getExtendedInfo()156     public CharSequence getExtendedInfo() {
157         return mExtendedInfo;
158     }
159 
getResolvedIntent()160     public Intent getResolvedIntent() {
161         return mResolvedIntent;
162     }
163 
164     @Override
getResolvedComponentName()165     public ComponentName getResolvedComponentName() {
166         return new ComponentName(mResolveInfo.activityInfo.packageName,
167                 mResolveInfo.activityInfo.name);
168     }
169 
170     @Override
start(Activity activity, Bundle options)171     public boolean start(Activity activity, Bundle options) {
172         activity.startActivity(mResolvedIntent, options);
173         return true;
174     }
175 
176     @Override
startAsCaller(ResolverActivity activity, Bundle options, int userId)177     public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
178         if (ENABLE_CHOOSER_DELEGATE) {
179             return activity.startAsCallerImpl(mResolvedIntent, options, false, userId);
180         } else {
181             activity.startActivityAsCaller(mResolvedIntent, options, null, false, userId);
182             return true;
183         }
184     }
185 
186     @Override
startAsUser(Activity activity, Bundle options, UserHandle user)187     public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
188         activity.startActivityAsUser(mResolvedIntent, options, user);
189         return false;
190     }
191 
isSuspended()192     public boolean isSuspended() {
193         return mIsSuspended;
194     }
195 
196     @Override
isPinned()197     public boolean isPinned() {
198         return mPinned;
199     }
200 
setPinned(boolean pinned)201     public void setPinned(boolean pinned) {
202         mPinned = pinned;
203     }
204 
205 }
206