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