blob: 0919911303916beeedbdd5afd8722af23869066b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 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
17package com.android.internal.app;
18
Hyunyoung Song16b7af42018-10-05 14:00:42 -070019import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
20
Adam Powell4c470d62015-06-19 17:46:17 -070021import android.annotation.Nullable;
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -070022import android.annotation.StringRes;
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -080023import android.annotation.UiThread;
Adam Powelle9414d92014-07-05 17:44:18 -070024import android.app.Activity;
Hakan Seyalioglu13405c52017-01-31 19:01:31 -080025import android.app.ActivityManager;
Wale Ogunwale04d9cb52018-04-30 13:55:07 -070026import android.app.ActivityTaskManager;
Dianne Hackborn028ceeb2014-08-17 17:45:48 -070027import android.app.ActivityThread;
Adam Powell4c470d62015-06-19 17:46:17 -070028import android.app.VoiceInteractor.PickOptionRequest;
29import android.app.VoiceInteractor.PickOptionRequest.Option;
30import android.app.VoiceInteractor.Prompt;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.content.ComponentName;
32import android.content.Context;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.content.Intent;
34import android.content.IntentFilter;
35import android.content.pm.ActivityInfo;
Sander Alewijnse6c9eee82014-07-17 10:03:31 +010036import android.content.pm.ApplicationInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -070037import android.content.pm.LabeledIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.content.pm.PackageManager;
Adam Powellc5878612012-05-04 18:42:38 -070039import android.content.pm.PackageManager.NameNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.content.pm.ResolveInfo;
Sander Alewijnse6c9eee82014-07-17 10:03:31 +010041import android.content.pm.UserInfo;
Jiongxuan Gao3365b162016-11-24 20:20:27 +090042import android.content.res.Configuration;
Adam Powellc5878612012-05-04 18:42:38 -070043import android.content.res.Resources;
Dianne Hackborneb034652009-09-07 00:49:58 -070044import android.graphics.drawable.Drawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.net.Uri;
Hakan Seyalioglu13405c52017-01-31 19:01:31 -080046import android.os.AsyncTask;
Sander Alewijnse6c9eee82014-07-17 10:03:31 +010047import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.Bundle;
Alison Cichowlas3e340502018-08-07 17:15:01 -040049import android.os.IBinder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.os.PatternMatcher;
Hakan Seyalioglu13405c52017-01-31 19:01:31 -080051import android.os.RemoteException;
Jeff Sharkey37355a92016-02-05 16:19:10 -070052import android.os.StrictMode;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070053import android.os.UserHandle;
Sander Alewijnse6c9eee82014-07-17 10:03:31 +010054import android.os.UserManager;
Hakan Seyalioglu13405c52017-01-31 19:01:31 -080055import android.provider.MediaStore;
56import android.provider.Settings;
57import android.text.TextUtils;
Hyunyoung Songdadb9e12017-08-24 18:08:35 -070058import android.util.IconDrawableFactory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.util.Log;
Hakan Seyalioglu13405c52017-01-31 19:01:31 -080060import android.util.Slog;
Adam Powell2d809622012-03-22 15:24:43 -070061import android.view.LayoutInflater;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.view.View;
63import android.view.ViewGroup;
Hakan Seyalioglu13405c52017-01-31 19:01:31 -080064import android.widget.AbsListView;
Adam Powell2d809622012-03-22 15:24:43 -070065import android.widget.AdapterView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import android.widget.BaseAdapter;
Adam Powellc5878612012-05-04 18:42:38 -070067import android.widget.Button;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068import android.widget.ImageView;
Adam Powell2d809622012-03-22 15:24:43 -070069import android.widget.ListView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.widget.TextView;
Sander Alewijnse6c9eee82014-07-17 10:03:31 +010071import android.widget.Toast;
Hyunyoung Song16b7af42018-10-05 14:00:42 -070072
Hakan Seyalioglu13405c52017-01-31 19:01:31 -080073import com.android.internal.R;
74import com.android.internal.annotations.VisibleForTesting;
75import com.android.internal.content.PackageMonitor;
Clara Bayarrifa902aa2016-04-13 14:45:08 +010076import com.android.internal.logging.MetricsLogger;
Tamas Berghammer383db5eb2016-06-22 15:21:38 +010077import com.android.internal.logging.nano.MetricsProto;
Adam Powell4f6c2052014-07-07 18:49:10 -070078import com.android.internal.widget.ResolverDrawerLayout;
Adam Powell2d809622012-03-22 15:24:43 -070079
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import java.util.ArrayList;
Clara Bayarrifa902aa2016-04-13 14:45:08 +010081import java.util.Arrays;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import java.util.HashSet;
83import java.util.Iterator;
84import java.util.List;
Adam Powellc412be62015-06-24 13:54:10 -070085import java.util.Objects;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086import java.util.Set;
87
88/**
89 * This activity is displayed when the system attempts to start an Intent for
90 * which there is more than one matching activity, allowing the user to decide
91 * which to go to. It is not normally used directly by application developers.
92 */
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -080093@UiThread
Adam Powell7d758002015-05-06 17:49:36 -070094public class ResolverActivity extends Activity {
Adam Powellc5878612012-05-04 18:42:38 -070095
Alison Cichowlas4691ed42018-11-13 15:59:55 -050096 // Temporary flag for new chooser delegate behavior.
Alison Cichowlas7b6f3b62018-12-07 09:06:57 -050097 boolean mEnableChooserDelegate = true;
Alison Cichowlas4691ed42018-11-13 15:59:55 -050098
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -080099 protected ResolveListAdapter mAdapter;
Dianne Hackborn028ceeb2014-08-17 17:45:48 -0700100 private boolean mSafeForwardingMode;
Adam Powell24428412015-04-01 17:19:56 -0700101 private AbsListView mAdapterView;
Adam Powellc5878612012-05-04 18:42:38 -0700102 private Button mAlwaysButton;
103 private Button mOnceButton;
shafik69df96322018-12-18 15:41:19 +0000104 private Button mSettingsButton;
Adam Powell88831a22014-11-20 18:17:00 -0800105 private View mProfileView;
Adam Powellc5878612012-05-04 18:42:38 -0700106 private int mIconDpi;
Adam Powell24428412015-04-01 17:19:56 -0700107 private int mLastSelected = AbsListView.INVALID_POSITION;
Sander Alewijnse6c9eee82014-07-17 10:03:31 +0100108 private boolean mResolvingHome = false;
Sander Alewijnsef6545332014-10-31 12:39:02 +0000109 private int mProfileSwitchMessageId = -1;
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800110 private int mLayoutId;
Adam Powell2ed547e2015-04-29 18:45:04 -0700111 private final ArrayList<Intent> mIntents = new ArrayList<>();
Adam Powell4c470d62015-06-19 17:46:17 -0700112 private PickTargetOptionRequest mPickOptionRequest;
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800113 private String mReferrerPackage;
Hakan Seyalioglu33550122017-01-06 19:54:43 -0800114 private CharSequence mTitle;
115 private int mDefaultTitleResId;
shafik69df96322018-12-18 15:41:19 +0000116 private boolean mUseLayoutForBrowsables;
Adam Powell09a65602014-07-20 16:23:14 -0700117
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800118 // Whether or not this activity supports choosing a default handler for the intent.
119 private boolean mSupportsAlwaysUseOption;
Adam Powell63b31692015-09-28 10:45:00 -0700120 protected ResolverDrawerLayout mResolverDrawerLayout;
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800121 protected PackageManager mPm;
122 protected int mLaunchedFromUid;
123
124 private static final String TAG = "ResolverActivity";
125 private static final boolean DEBUG = false;
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800126 private Runnable mPostListReadyRunnable;
Adam Powell63b31692015-09-28 10:45:00 -0700127
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700128 private boolean mRegistered;
Jorim Jaggif631ef72017-02-24 13:49:47 +0100129
130 /** See {@link #setRetainInOnStop}. */
131 private boolean mRetainInOnStop;
132
Hyunyoung Songdadb9e12017-08-24 18:08:35 -0700133 IconDrawableFactory mIconFactory;
134
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800135 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
136 @Override public void onSomePackagesChanged() {
137 mAdapter.handlePackagesChanged();
Adam Powell88831a22014-11-20 18:17:00 -0800138 if (mProfileView != null) {
139 bindProfileView();
140 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800141 }
Xiaohui Chen393c8012017-02-14 14:55:07 -0800142
143 @Override
144 public boolean onPackageChanged(String packageName, int uid, String[] components) {
145 // We care about all package changes, not just the whole package itself which is
146 // default behavior.
147 return true;
148 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800149 };
150
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -0700151 /**
152 * Get the string resource to be used as a label for the link to the resolver activity for an
153 * action.
154 *
155 * @param action The action to resolve
156 *
157 * @return The string resource to be used as a label
158 */
159 public static @StringRes int getLabelRes(String action) {
160 return ActionTitle.forAction(action).labelRes;
161 }
162
Adam Powell278902c2014-07-12 18:33:22 -0700163 private enum ActionTitle {
164 VIEW(Intent.ACTION_VIEW,
165 com.android.internal.R.string.whichViewApplication,
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -0700166 com.android.internal.R.string.whichViewApplicationNamed,
167 com.android.internal.R.string.whichViewApplicationLabel),
Adam Powell278902c2014-07-12 18:33:22 -0700168 EDIT(Intent.ACTION_EDIT,
169 com.android.internal.R.string.whichEditApplication,
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -0700170 com.android.internal.R.string.whichEditApplicationNamed,
171 com.android.internal.R.string.whichEditApplicationLabel),
Adam Powell278902c2014-07-12 18:33:22 -0700172 SEND(Intent.ACTION_SEND,
173 com.android.internal.R.string.whichSendApplication,
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -0700174 com.android.internal.R.string.whichSendApplicationNamed,
175 com.android.internal.R.string.whichSendApplicationLabel),
Adam Powell278902c2014-07-12 18:33:22 -0700176 SENDTO(Intent.ACTION_SENDTO,
Adam Powell13ea8f42016-03-18 09:39:41 -0700177 com.android.internal.R.string.whichSendToApplication,
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -0700178 com.android.internal.R.string.whichSendToApplicationNamed,
179 com.android.internal.R.string.whichSendToApplicationLabel),
Adam Powell278902c2014-07-12 18:33:22 -0700180 SEND_MULTIPLE(Intent.ACTION_SEND_MULTIPLE,
181 com.android.internal.R.string.whichSendApplication,
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -0700182 com.android.internal.R.string.whichSendApplicationNamed,
183 com.android.internal.R.string.whichSendApplicationLabel),
184 CAPTURE_IMAGE(MediaStore.ACTION_IMAGE_CAPTURE,
185 com.android.internal.R.string.whichImageCaptureApplication,
186 com.android.internal.R.string.whichImageCaptureApplicationNamed,
187 com.android.internal.R.string.whichImageCaptureApplicationLabel),
Adam Powell278902c2014-07-12 18:33:22 -0700188 DEFAULT(null,
189 com.android.internal.R.string.whichApplication,
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -0700190 com.android.internal.R.string.whichApplicationNamed,
191 com.android.internal.R.string.whichApplicationLabel),
Adam Powella35c77a2014-09-25 16:46:36 -0700192 HOME(Intent.ACTION_MAIN,
193 com.android.internal.R.string.whichHomeApplication,
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -0700194 com.android.internal.R.string.whichHomeApplicationNamed,
195 com.android.internal.R.string.whichHomeApplicationLabel);
Adam Powell278902c2014-07-12 18:33:22 -0700196
shafik69df96322018-12-18 15:41:19 +0000197 // SpR.id.buttonecial titles for BROWSABLE components
198 public static final int BROWSABLE_TITLE_RES =
199 com.android.internal.R.string.whichGiveAccessToApplication;
200 public static final int BROWSABLE_NAMED_TITLE_RES =
201 com.android.internal.R.string.whichGiveAccessToApplicationNamed;
202
Adam Powell278902c2014-07-12 18:33:22 -0700203 public final String action;
204 public final int titleRes;
205 public final int namedTitleRes;
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -0700206 public final @StringRes int labelRes;
Adam Powell278902c2014-07-12 18:33:22 -0700207
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -0700208 ActionTitle(String action, int titleRes, int namedTitleRes, @StringRes int labelRes) {
Adam Powell278902c2014-07-12 18:33:22 -0700209 this.action = action;
210 this.titleRes = titleRes;
211 this.namedTitleRes = namedTitleRes;
Philip P. Moltmannf8173ca2016-04-12 15:11:23 -0700212 this.labelRes = labelRes;
Adam Powell278902c2014-07-12 18:33:22 -0700213 }
214
215 public static ActionTitle forAction(String action) {
216 for (ActionTitle title : values()) {
Adam Powella35c77a2014-09-25 16:46:36 -0700217 if (title != HOME && action != null && action.equals(title.action)) {
Adam Powell278902c2014-07-12 18:33:22 -0700218 return title;
219 }
220 }
221 return DEFAULT;
222 }
223 }
224
Dianne Hackborn905577f2011-09-07 18:31:28 -0700225 private Intent makeMyIntent() {
226 Intent intent = new Intent(getIntent());
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700227 intent.setComponent(null);
Dianne Hackborn905577f2011-09-07 18:31:28 -0700228 // The resolver activity is set to be hidden from recent tasks.
229 // we don't want this attribute to be propagated to the next activity
230 // being launched. Note that if the original Intent also had this
231 // flag set, we are now losing it. That should be a very rare case
232 // and we can live with this.
233 intent.setFlags(intent.getFlags()&~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
234 return intent;
235 }
236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 @Override
238 protected void onCreate(Bundle savedInstanceState) {
Christopher Tateb72b3632013-09-30 17:50:32 -0700239 // Use a specialized prompt when we're handling the 'Home' app startActivity()
Christopher Tateb72b3632013-09-30 17:50:32 -0700240 final Intent intent = makeMyIntent();
241 final Set<String> categories = intent.getCategories();
242 if (Intent.ACTION_MAIN.equals(intent.getAction())
243 && categories != null
244 && categories.size() == 1
245 && categories.contains(Intent.CATEGORY_HOME)) {
Sander Alewijnse6c9eee82014-07-17 10:03:31 +0100246 // Note: this field is not set to true in the compatibility version.
247 mResolvingHome = true;
Christopher Tateb72b3632013-09-30 17:50:32 -0700248 }
249
Dianne Hackborn028ceeb2014-08-17 17:45:48 -0700250 setSafeForwardingMode(true);
251
Adam Powella35c77a2014-09-25 16:46:36 -0700252 onCreate(savedInstanceState, intent, null, 0, null, null, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 }
254
Adam Powell278902c2014-07-12 18:33:22 -0700255 /**
Adam Powell24428412015-04-01 17:19:56 -0700256 * Compatibility version for other bundled services that use this overload without
Adam Powell278902c2014-07-12 18:33:22 -0700257 * a default title resource
258 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 protected void onCreate(Bundle savedInstanceState, Intent intent,
Adam Powell278902c2014-07-12 18:33:22 -0700260 CharSequence title, Intent[] initialIntents,
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800261 List<ResolveInfo> rList, boolean supportsAlwaysUseOption) {
262 onCreate(savedInstanceState, intent, title, 0, initialIntents, rList,
263 supportsAlwaysUseOption);
Adam Powell278902c2014-07-12 18:33:22 -0700264 }
265
266 protected void onCreate(Bundle savedInstanceState, Intent intent,
267 CharSequence title, int defaultTitleRes, Intent[] initialIntents,
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800268 List<ResolveInfo> rList, boolean supportsAlwaysUseOption) {
Adam Powelle9414d92014-07-05 17:44:18 -0700269 setTheme(R.style.Theme_DeviceDefault_Resolver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 super.onCreate(savedInstanceState);
Sander Alewijnsef6545332014-10-31 12:39:02 +0000271
272 // Determine whether we should show that intent is forwarded
273 // from managed profile to owner or other way around.
274 setProfileSwitchMessageId(intent.getContentUserHint());
275
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700276 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700277 mLaunchedFromUid = ActivityTaskManager.getService().getLaunchedFromUid(
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700278 getActivityToken());
279 } catch (RemoteException e) {
280 mLaunchedFromUid = -1;
281 }
Adam Powell7d758002015-05-06 17:49:36 -0700282
283 if (mLaunchedFromUid < 0 || UserHandle.isIsolated(mLaunchedFromUid)) {
284 // Gulp!
285 finish();
286 return;
287 }
288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 mPm = getPackageManager();
Adam Powell09a65602014-07-20 16:23:14 -0700290
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700291 mPackageMonitor.register(this, getMainLooper(), false);
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700292 mRegistered = true;
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800293 mReferrerPackage = getReferrerPackageName();
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800294
Adam Powellc5878612012-05-04 18:42:38 -0700295 final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
296 mIconDpi = am.getLauncherLargeIconDensity();
Adam Powellc5878612012-05-04 18:42:38 -0700297
Adam Powell7d758002015-05-06 17:49:36 -0700298 // Add our initial intent as the first item, regardless of what else has already been added.
Adam Powell2ed547e2015-04-29 18:45:04 -0700299 mIntents.add(0, new Intent(intent));
Hakan Seyalioglu33550122017-01-06 19:54:43 -0800300 mTitle = title;
301 mDefaultTitleResId = defaultTitleRes;
Adam Powell278902c2014-07-12 18:33:22 -0700302
shafik69df96322018-12-18 15:41:19 +0000303 mUseLayoutForBrowsables = getTargetIntent() == null
304 ? false
305 : getTargetIntent().hasCategory(Intent.CATEGORY_BROWSABLE);
306
307 // We don't want to support Always Use if browsable layout is being used,
308 // as to mitigate Intent Capturing vulnerability
309 mSupportsAlwaysUseOption = supportsAlwaysUseOption && !mUseLayoutForBrowsables;
310
Hyunyoung Song16b7af42018-10-05 14:00:42 -0700311 mIconFactory = IconDrawableFactory.newInstance(this, true);
Hakan Seyalioglu33550122017-01-06 19:54:43 -0800312 if (configureContentView(mIntents, initialIntents, rList)) {
Adam Powell39e94eb2015-09-08 17:01:49 -0700313 return;
314 }
Adam Powell278902c2014-07-12 18:33:22 -0700315
Alan Viverette51efddb2017-04-05 10:00:01 -0400316 final ResolverDrawerLayout rdl = findViewById(R.id.contentPanel);
Adam Powell4f6c2052014-07-07 18:49:10 -0700317 if (rdl != null) {
Adam Powell5dd072d2014-10-30 19:51:41 -0700318 rdl.setOnDismissedListener(new ResolverDrawerLayout.OnDismissedListener() {
Adam Powell4f6c2052014-07-07 18:49:10 -0700319 @Override
Adam Powell5dd072d2014-10-30 19:51:41 -0700320 public void onDismissed() {
Adam Powell4f6c2052014-07-07 18:49:10 -0700321 finish();
322 }
323 });
Adam Powell4c470d62015-06-19 17:46:17 -0700324 if (isVoiceInteraction()) {
325 rdl.setCollapsed(false);
326 }
Adam Powell63b31692015-09-28 10:45:00 -0700327 mResolverDrawerLayout = rdl;
Adam Powell4f6c2052014-07-07 18:49:10 -0700328 }
329
Adam Powell88831a22014-11-20 18:17:00 -0800330 mProfileView = findViewById(R.id.profile_button);
331 if (mProfileView != null) {
332 mProfileView.setOnClickListener(new View.OnClickListener() {
333 @Override
334 public void onClick(View v) {
335 final DisplayResolveInfo dri = mAdapter.getOtherProfile();
336 if (dri == null) {
337 return;
338 }
339
Sander Alewijnse053d3dd2015-03-09 15:31:10 +0000340 // Do not show the profile switch message anymore.
341 mProfileSwitchMessageId = -1;
342
Adam Powell24428412015-04-01 17:19:56 -0700343 onTargetSelected(dri, false);
Adam Powell88831a22014-11-20 18:17:00 -0800344 finish();
345 }
346 });
347 bindProfileView();
348 }
Adam Powell4c470d62015-06-19 17:46:17 -0700349
350 if (isVoiceInteraction()) {
351 onSetupVoiceInteraction();
352 }
Clara Bayarri9550f5d2016-05-11 11:20:13 +0100353 final Set<String> categories = intent.getCategories();
Clara Bayarrifa902aa2016-04-13 14:45:08 +0100354 MetricsLogger.action(this, mAdapter.hasFilteredItem()
355 ? MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_APP_FEATURED
356 : MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_NONE_FEATURED,
357 intent.getAction() + ":" + intent.getType() + ":"
Clara Bayarri9550f5d2016-05-11 11:20:13 +0100358 + (categories != null ? Arrays.toString(categories.toArray()) : ""));
Adam Powell4c470d62015-06-19 17:46:17 -0700359 }
360
Jiongxuan Gao3365b162016-11-24 20:20:27 +0900361 @Override
362 public void onConfigurationChanged(Configuration newConfig) {
363 super.onConfigurationChanged(newConfig);
364 mAdapter.handlePackagesChanged();
365 }
366
Adam Powell4c470d62015-06-19 17:46:17 -0700367 /**
368 * Perform any initialization needed for voice interaction.
369 */
Adam Powell23882512016-01-29 10:21:00 -0800370 public void onSetupVoiceInteraction() {
Adam Powell4c470d62015-06-19 17:46:17 -0700371 // Do it right now. Subclasses may delay this and send it later.
372 sendVoiceChoicesIfNeeded();
373 }
374
Adam Powell23882512016-01-29 10:21:00 -0800375 public void sendVoiceChoicesIfNeeded() {
Adam Powell4c470d62015-06-19 17:46:17 -0700376 if (!isVoiceInteraction()) {
377 // Clearly not needed.
378 return;
379 }
380
381
382 final Option[] options = new Option[mAdapter.getCount()];
383 for (int i = 0, N = options.length; i < N; i++) {
384 options[i] = optionForChooserTarget(mAdapter.getItem(i), i);
385 }
386
387 mPickOptionRequest = new PickTargetOptionRequest(
388 new Prompt(getTitle()), options, null);
389 getVoiceInteractor().submitRequest(mPickOptionRequest);
390 }
391
392 Option optionForChooserTarget(TargetInfo target, int index) {
393 return new Option(target.getDisplayLabel(), index);
Adam Powell88831a22014-11-20 18:17:00 -0800394 }
395
Adam Powell2ed547e2015-04-29 18:45:04 -0700396 protected final void setAdditionalTargets(Intent[] intents) {
397 if (intents != null) {
398 for (Intent intent : intents) {
399 mIntents.add(intent);
400 }
401 }
402 }
403
Adam Powell0ccc0e92015-04-23 17:19:37 -0700404 public Intent getTargetIntent() {
Adam Powell2ed547e2015-04-29 18:45:04 -0700405 return mIntents.isEmpty() ? null : mIntents.get(0);
Adam Powell0ccc0e92015-04-23 17:19:37 -0700406 }
407
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800408 protected String getReferrerPackageName() {
Adam Powell24428412015-04-01 17:19:56 -0700409 final Uri referrer = getReferrer();
410 if (referrer != null && "android-app".equals(referrer.getScheme())) {
411 return referrer.getHost();
412 }
413 return null;
414 }
415
Adam Powell23882512016-01-29 10:21:00 -0800416 public int getLayoutResource() {
Adam Powell24428412015-04-01 17:19:56 -0700417 return R.layout.resolver_list;
418 }
419
Adam Powell88831a22014-11-20 18:17:00 -0800420 void bindProfileView() {
421 final DisplayResolveInfo dri = mAdapter.getOtherProfile();
422 if (dri != null) {
423 mProfileView.setVisibility(View.VISIBLE);
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800424 View text = mProfileView.findViewById(R.id.profile_button);
425 if (!(text instanceof TextView)) {
426 text = mProfileView.findViewById(R.id.text1);
427 }
428 ((TextView) text).setText(dri.getDisplayLabel());
Adam Powell88831a22014-11-20 18:17:00 -0800429 } else {
430 mProfileView.setVisibility(View.GONE);
431 }
Adam Powell278902c2014-07-12 18:33:22 -0700432 }
433
Sander Alewijnsef6545332014-10-31 12:39:02 +0000434 private void setProfileSwitchMessageId(int contentUserHint) {
435 if (contentUserHint != UserHandle.USER_CURRENT &&
436 contentUserHint != UserHandle.myUserId()) {
437 UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
438 UserInfo originUserInfo = userManager.getUserInfo(contentUserHint);
439 boolean originIsManaged = originUserInfo != null ? originUserInfo.isManagedProfile()
440 : false;
441 boolean targetIsManaged = userManager.isManagedProfile();
442 if (originIsManaged && !targetIsManaged) {
443 mProfileSwitchMessageId = com.android.internal.R.string.forward_intent_to_owner;
444 } else if (!originIsManaged && targetIsManaged) {
445 mProfileSwitchMessageId = com.android.internal.R.string.forward_intent_to_work;
446 }
447 }
448 }
449
Dianne Hackborn028ceeb2014-08-17 17:45:48 -0700450 /**
451 * Turn on launch mode that is safe to use when forwarding intents received from
452 * applications and running in system processes. This mode uses Activity.startActivityAsCaller
453 * instead of the normal Activity.startActivity for launching the activity selected
454 * by the user.
455 *
456 * <p>This mode is set to true by default if the activity is initialized through
457 * {@link #onCreate(android.os.Bundle)}. If a subclass calls one of the other onCreate
458 * methods, it is set to false by default. You must set it before calling one of the
459 * more detailed onCreate methods, so that it will be set correctly in the case where
460 * there is only one intent to resolve and it is thus started immediately.</p>
461 */
462 public void setSafeForwardingMode(boolean safeForwarding) {
463 mSafeForwardingMode = safeForwarding;
464 }
465
shafik69df96322018-12-18 15:41:19 +0000466 protected CharSequence getTitleForAction(Intent intent, int defaultTitleRes) {
467 final ActionTitle title = mResolvingHome
468 ? ActionTitle.HOME
469 : ActionTitle.forAction(intent.getAction());
470
Hakan Seyalioglu23f34652017-02-03 09:38:35 -0800471 // While there may already be a filtered item, we can only use it in the title if the list
472 // is already sorted and all information relevant to it is already in the list.
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800473 final boolean named = mAdapter.getFilteredPosition() >= 0;
Adam Powell278902c2014-07-12 18:33:22 -0700474 if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) {
475 return getString(defaultTitleRes);
shafik69df96322018-12-18 15:41:19 +0000476 } else if (intent.hasCategory(Intent.CATEGORY_BROWSABLE)) {
477 // If the Intent is BROWSABLE then we need to warn the user that
478 // they're giving access for the activity to open URLs from this specific host
479 return named
480 ? getString(ActionTitle.BROWSABLE_NAMED_TITLE_RES, intent.getData().getHost(),
481 mAdapter.getFilteredItem().getDisplayLabel())
482 : getString(ActionTitle.BROWSABLE_TITLE_RES, intent.getData().getHost());
Adam Powell278902c2014-07-12 18:33:22 -0700483 } else {
Adam Powell24428412015-04-01 17:19:56 -0700484 return named
485 ? getString(title.namedTitleRes, mAdapter.getFilteredItem().getDisplayLabel())
486 : getString(title.titleRes);
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700487 }
Adam Powellc5878612012-05-04 18:42:38 -0700488 }
489
Adam Powelle9414d92014-07-05 17:44:18 -0700490 void dismiss() {
491 if (!isFinishing()) {
492 finish();
493 }
494 }
495
Adam Powellc5878612012-05-04 18:42:38 -0700496 Drawable getIcon(Resources res, int resId) {
497 Drawable result;
498 try {
499 result = res.getDrawableForDensity(resId, mIconDpi);
500 } catch (Resources.NotFoundException e) {
501 result = null;
502 }
503
504 return result;
505 }
506
507 Drawable loadIconForResolveInfo(ResolveInfo ri) {
508 Drawable dr;
509 try {
510 if (ri.resolvePackageName != null && ri.icon != 0) {
511 dr = getIcon(mPm.getResourcesForApplication(ri.resolvePackageName), ri.icon);
512 if (dr != null) {
Hyunyoung Songdadb9e12017-08-24 18:08:35 -0700513 return mIconFactory.getShadowedIcon(dr);
Adam Powellc5878612012-05-04 18:42:38 -0700514 }
515 }
516 final int iconRes = ri.getIconResource();
517 if (iconRes != 0) {
518 dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.packageName), iconRes);
519 if (dr != null) {
Hyunyoung Songdadb9e12017-08-24 18:08:35 -0700520 return mIconFactory.getShadowedIcon(dr);
Adam Powellc5878612012-05-04 18:42:38 -0700521 }
522 }
523 } catch (NameNotFoundException e) {
524 Log.e(TAG, "Couldn't find resources for package", e);
525 }
Hyunyoung Songdadb9e12017-08-24 18:08:35 -0700526 return mIconFactory.getBadgedIcon(ri.activityInfo.applicationInfo);
Adam Powellc5878612012-05-04 18:42:38 -0700527 }
528
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800529 @Override
530 protected void onRestart() {
531 super.onRestart();
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700532 if (!mRegistered) {
533 mPackageMonitor.register(this, getMainLooper(), false);
534 mRegistered = true;
535 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800536 mAdapter.handlePackagesChanged();
Adam Powell88831a22014-11-20 18:17:00 -0800537 if (mProfileView != null) {
538 bindProfileView();
539 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800540 }
541
542 @Override
543 protected void onStop() {
544 super.onStop();
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700545 if (mRegistered) {
546 mPackageMonitor.unregister();
547 mRegistered = false;
548 }
Wale Ogunwale9014e662016-03-19 14:55:46 -0700549 final Intent intent = getIntent();
550 if ((intent.getFlags() & FLAG_ACTIVITY_NEW_TASK) != 0 && !isVoiceInteraction()
Jorim Jaggif631ef72017-02-24 13:49:47 +0100551 && !mResolvingHome && !mRetainInOnStop) {
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700552 // This resolver is in the unusual situation where it has been
553 // launched at the top of a new task. We don't let it be added
554 // to the recent tasks shown to the user, and we need to make sure
555 // that each time we are launched we get the correct launching
556 // uid (not re-using the same resolver from an old launching uid),
557 // so we will now finish ourself since being no longer visible,
558 // the user probably can't get back to us.
559 if (!isChangingConfigurations()) {
560 finish();
561 }
562 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800563 }
564
Adam Powellc5878612012-05-04 18:42:38 -0700565 @Override
Adam Powell4c470d62015-06-19 17:46:17 -0700566 protected void onDestroy() {
567 super.onDestroy();
568 if (!isChangingConfigurations() && mPickOptionRequest != null) {
569 mPickOptionRequest.cancel();
570 }
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800571 if (mPostListReadyRunnable != null) {
572 getMainThreadHandler().removeCallbacks(mPostListReadyRunnable);
573 mPostListReadyRunnable = null;
Hakan Seyalioglu23f34652017-02-03 09:38:35 -0800574 }
Kang Li38a6da642017-04-05 12:30:55 -0700575 if (mAdapter != null && mAdapter.mResolverListController != null) {
576 mAdapter.mResolverListController.destroy();
577 }
Adam Powell4c470d62015-06-19 17:46:17 -0700578 }
579
580 @Override
Adam Powell9bee4662012-05-08 11:07:23 -0700581 protected void onRestoreInstanceState(Bundle savedInstanceState) {
582 super.onRestoreInstanceState(savedInstanceState);
shafik69df96322018-12-18 15:41:19 +0000583 resetButtonBar();
Adam Powell9bee4662012-05-08 11:07:23 -0700584 }
585
Sander Alewijnse6c9eee82014-07-17 10:03:31 +0100586 private boolean hasManagedProfile() {
587 UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE);
588 if (userManager == null) {
589 return false;
590 }
591
592 try {
593 List<UserInfo> profiles = userManager.getProfiles(getUserId());
594 for (UserInfo userInfo : profiles) {
595 if (userInfo != null && userInfo.isManagedProfile()) {
596 return true;
597 }
598 }
599 } catch (SecurityException e) {
600 return false;
601 }
602 return false;
603 }
604
605 private boolean supportsManagedProfiles(ResolveInfo resolveInfo) {
606 try {
607 ApplicationInfo appInfo = getPackageManager().getApplicationInfo(
608 resolveInfo.activityInfo.packageName, 0 /* default flags */);
Adam Powell4c470d62015-06-19 17:46:17 -0700609 return appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
Sander Alewijnse6c9eee82014-07-17 10:03:31 +0100610 } catch (NameNotFoundException e) {
611 return false;
612 }
613 }
614
Adam Powell278902c2014-07-12 18:33:22 -0700615 private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos,
616 boolean filtered) {
Nicolas Prevot50449882014-06-23 12:42:37 +0100617 boolean enabled = false;
618 if (hasValidSelection) {
Adam Powell278902c2014-07-12 18:33:22 -0700619 ResolveInfo ri = mAdapter.resolveInfoForPosition(checkedPos, filtered);
Hakan Seyalioglu5dbc8192017-02-24 16:16:37 -0800620 if (ri == null) {
621 Log.e(TAG, "Invalid position supplied to setAlwaysButtonEnabled");
622 return;
623 } else if (ri.targetUserId != UserHandle.USER_CURRENT) {
624 Log.e(TAG, "Attempted to set selection to resolve info for another user");
625 return;
626 } else {
Nicolas Prevot50449882014-06-23 12:42:37 +0100627 enabled = true;
628 }
629 }
630 mAlwaysButton.setEnabled(enabled);
631 }
632
Adam Powellc5878612012-05-04 18:42:38 -0700633 public void onButtonClick(View v) {
634 final int id = v.getId();
shafik69df96322018-12-18 15:41:19 +0000635 int which = mAdapter.hasFilteredItem()
636 ? mAdapter.getFilteredPosition()
637 : mAdapterView.getCheckedItemPosition();
638 boolean hasIndexBeenFiltered = !mAdapter.hasFilteredItem();
639 if (id == R.id.button_app_settings) {
640 showSettingsForSelected(which, hasIndexBeenFiltered);
641 } else {
642 startSelected(which, id == R.id.button_always, hasIndexBeenFiltered);
643 }
644 }
645
646 private void showSettingsForSelected(int which, boolean hasIndexBeenFiltered) {
647 ResolveInfo ri = mAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered);
648 Intent in = new Intent().setAction(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS)
649 .setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
650 .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
651 startActivity(in);
Adam Powellc5878612012-05-04 18:42:38 -0700652 }
653
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800654 public void startSelected(int which, boolean always, boolean hasIndexBeenFiltered) {
Amith Yamasani07cd3512013-09-18 13:16:00 -0700655 if (isFinishing()) {
656 return;
657 }
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800658 ResolveInfo ri = mAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered);
Sander Alewijnse86d35ba2015-02-04 15:14:53 +0000659 if (mResolvingHome && hasManagedProfile() && !supportsManagedProfiles(ri)) {
660 Toast.makeText(this, String.format(getResources().getString(
661 com.android.internal.R.string.activity_resolver_work_profiles_support),
662 ri.activityInfo.loadLabel(getPackageManager()).toString()),
663 Toast.LENGTH_LONG).show();
664 return;
665 }
666
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800667 TargetInfo target = mAdapter.targetInfoForPosition(which, hasIndexBeenFiltered);
Hakan Seyalioglu23f34652017-02-03 09:38:35 -0800668 if (target == null) {
669 return;
670 }
Adam Powell2ed547e2015-04-29 18:45:04 -0700671 if (onTargetSelected(target, always)) {
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800672 if (always && mSupportsAlwaysUseOption) {
Clara Bayarrifa902aa2016-04-13 14:45:08 +0100673 MetricsLogger.action(
674 this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_ALWAYS);
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800675 } else if (mSupportsAlwaysUseOption) {
Clara Bayarrifa902aa2016-04-13 14:45:08 +0100676 MetricsLogger.action(
677 this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_JUST_ONCE);
678 } else {
679 MetricsLogger.action(
680 this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_TAP);
681 }
682 MetricsLogger.action(this, mAdapter.hasFilteredItem()
683 ? MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_APP_FEATURED
684 : MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_NONE_FEATURED);
Adam Powell2ed547e2015-04-29 18:45:04 -0700685 finish();
686 }
Mike Lockwood02eb8742011-02-27 09:10:37 -0800687 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688
Adam Powelle49d9392014-07-17 18:45:19 -0700689 /**
690 * Replace me in subclasses!
691 */
Nicolas Prevot0e2b73f2014-10-27 10:06:11 +0000692 public Intent getReplacementIntent(ActivityInfo aInfo, Intent defIntent) {
Adam Powelle49d9392014-07-17 18:45:19 -0700693 return defIntent;
694 }
695
Adam Powell2ed547e2015-04-29 18:45:04 -0700696 protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
Adam Powell24428412015-04-01 17:19:56 -0700697 final ResolveInfo ri = target.getResolveInfo();
698 final Intent intent = target != null ? target.getResolvedIntent() : null;
699
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800700 if (intent != null && (mSupportsAlwaysUseOption || mAdapter.hasFilteredItem())
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800701 && mAdapter.mUnfilteredResolveList != null) {
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700702 // Build a reasonable intent filter, based on what matched.
703 IntentFilter filter = new IntentFilter();
Henrik Engström3277cf12014-07-17 12:18:29 +0200704 Intent filterIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705
Henrik Engström3277cf12014-07-17 12:18:29 +0200706 if (intent.getSelector() != null) {
707 filterIntent = intent.getSelector();
708 } else {
709 filterIntent = intent;
710 }
711
712 String action = filterIntent.getAction();
Fabrice Di Meglio1c1b4712014-11-19 17:12:32 -0800713 if (action != null) {
714 filter.addAction(action);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 }
Henrik Engström3277cf12014-07-17 12:18:29 +0200716 Set<String> categories = filterIntent.getCategories();
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700717 if (categories != null) {
718 for (String cat : categories) {
719 filter.addCategory(cat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 }
721 }
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700722 filter.addCategory(Intent.CATEGORY_DEFAULT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723
Adam Powell24428412015-04-01 17:19:56 -0700724 int cat = ri.match & IntentFilter.MATCH_CATEGORY_MASK;
Henrik Engström3277cf12014-07-17 12:18:29 +0200725 Uri data = filterIntent.getData();
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700726 if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
Henrik Engström3277cf12014-07-17 12:18:29 +0200727 String mimeType = filterIntent.resolveType(this);
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700728 if (mimeType != null) {
729 try {
730 filter.addDataType(mimeType);
731 } catch (IntentFilter.MalformedMimeTypeException e) {
732 Log.w("ResolverActivity", e);
733 filter = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 }
735 }
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700736 }
737 if (data != null && data.getScheme() != null) {
738 // We need the data specification if there was no type,
739 // OR if the scheme is not one of our magical "file:"
740 // or "content:" schemes (see IntentFilter for the reason).
741 if (cat != IntentFilter.MATCH_CATEGORY_TYPE
742 || (!"file".equals(data.getScheme())
743 && !"content".equals(data.getScheme()))) {
744 filter.addDataScheme(data.getScheme());
745
746 // Look through the resolved filter to determine which part
747 // of it matched the original Intent.
748 Iterator<PatternMatcher> pIt = ri.filter.schemeSpecificPartsIterator();
749 if (pIt != null) {
750 String ssp = data.getSchemeSpecificPart();
751 while (ssp != null && pIt.hasNext()) {
752 PatternMatcher p = pIt.next();
753 if (p.match(ssp)) {
754 filter.addDataSchemeSpecificPart(p.getPath(), p.getType());
755 break;
756 }
Dianne Hackborndf1c0bf2013-06-12 16:21:38 -0700757 }
758 }
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700759 Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();
760 if (aIt != null) {
761 while (aIt.hasNext()) {
762 IntentFilter.AuthorityEntry a = aIt.next();
763 if (a.match(data) >= 0) {
764 int port = a.getPort();
765 filter.addDataAuthority(a.getHost(),
766 port >= 0 ? Integer.toString(port) : null);
767 break;
768 }
769 }
770 }
771 pIt = ri.filter.pathsIterator();
772 if (pIt != null) {
773 String path = data.getPath();
774 while (path != null && pIt.hasNext()) {
775 PatternMatcher p = pIt.next();
776 if (p.match(path)) {
777 filter.addDataPath(p.getPath(), p.getType());
778 break;
779 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 }
781 }
782 }
783 }
784
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700785 if (filter != null) {
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800786 final int N = mAdapter.mUnfilteredResolveList.size();
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800787 ComponentName[] set;
788 // If we don't add back in the component for forwarding the intent to a managed
789 // profile, the preferred activity may not be updated correctly (as the set of
790 // components we tell it we knew about will have changed).
791 final boolean needToAddBackProfileForwardingComponent
792 = mAdapter.mOtherProfile != null;
793 if (!needToAddBackProfileForwardingComponent) {
794 set = new ComponentName[N];
795 } else {
796 set = new ComponentName[N + 1];
797 }
798
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700799 int bestMatch = 0;
800 for (int i=0; i<N; i++) {
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800801 ResolveInfo r = mAdapter.mUnfilteredResolveList.get(i).getResolveInfoAt(0);
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700802 set[i] = new ComponentName(r.activityInfo.packageName,
803 r.activityInfo.name);
804 if (r.match > bestMatch) bestMatch = r.match;
805 }
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800806
807 if (needToAddBackProfileForwardingComponent) {
808 set[N] = mAdapter.mOtherProfile.getResolvedComponentName();
809 final int otherProfileMatch = mAdapter.mOtherProfile.getResolveInfo().match;
810 if (otherProfileMatch > bestMatch) bestMatch = otherProfileMatch;
811 }
812
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700813 if (alwaysCheck) {
Fabrice Di Meglio3453e082015-05-11 17:46:23 -0700814 final int userId = getUserId();
815 final PackageManager pm = getPackageManager();
Fabrice Di Meglio1c1b4712014-11-19 17:12:32 -0800816
817 // Set the preferred Activity
818 pm.addPreferredActivity(filter, bestMatch, set, intent.getComponent());
819
Fabrice Di Meglio3453e082015-05-11 17:46:23 -0700820 if (ri.handleAllWebDataURI) {
821 // Set default Browser if needed
Jeff Sharkeye06b4d12016-01-06 14:51:50 -0700822 final String packageName = pm.getDefaultBrowserPackageNameAsUser(userId);
Fabrice Di Meglio3453e082015-05-11 17:46:23 -0700823 if (TextUtils.isEmpty(packageName)) {
Jeff Sharkeye06b4d12016-01-06 14:51:50 -0700824 pm.setDefaultBrowserPackageNameAsUser(ri.activityInfo.packageName, userId);
Fabrice Di Meglio3453e082015-05-11 17:46:23 -0700825 }
826 } else {
827 // Update Domain Verification status
828 ComponentName cn = intent.getComponent();
829 String packageName = cn.getPackageName();
830 String dataScheme = (data != null) ? data.getScheme() : null;
Fabrice Di Meglio1c1b4712014-11-19 17:12:32 -0800831
Fabrice Di Meglio3453e082015-05-11 17:46:23 -0700832 boolean isHttpOrHttps = (dataScheme != null) &&
833 (dataScheme.equals(IntentFilter.SCHEME_HTTP) ||
834 dataScheme.equals(IntentFilter.SCHEME_HTTPS));
Fabrice Di Meglio1c1b4712014-11-19 17:12:32 -0800835
Fabrice Di Meglio3453e082015-05-11 17:46:23 -0700836 boolean isViewAction = (action != null) && action.equals(Intent.ACTION_VIEW);
837 boolean hasCategoryBrowsable = (categories != null) &&
838 categories.contains(Intent.CATEGORY_BROWSABLE);
Fabrice Di Meglio1c1b4712014-11-19 17:12:32 -0800839
Fabrice Di Meglio3453e082015-05-11 17:46:23 -0700840 if (isHttpOrHttps && isViewAction && hasCategoryBrowsable) {
Jeff Sharkeye06b4d12016-01-06 14:51:50 -0700841 pm.updateIntentVerificationStatusAsUser(packageName,
Fabrice Di Meglio3453e082015-05-11 17:46:23 -0700842 PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS,
843 userId);
844 }
Fabrice Di Meglio1c1b4712014-11-19 17:12:32 -0800845 }
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700846 } else {
847 try {
Hakan Seyalioglu9149dca2017-01-17 12:20:01 -0800848 mAdapter.mResolverListController.setLastChosen(intent, filter, bestMatch);
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700849 } catch (RemoteException re) {
850 Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
851 }
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700852 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
854 }
855
Adam Powell24428412015-04-01 17:19:56 -0700856 if (target != null) {
857 safelyStartActivity(target);
Dianne Hackborn028ceeb2014-08-17 17:45:48 -0700858 }
Adam Powell2ed547e2015-04-29 18:45:04 -0700859 return true;
Dianne Hackborn028ceeb2014-08-17 17:45:48 -0700860 }
861
Adam Powell23882512016-01-29 10:21:00 -0800862 public void safelyStartActivity(TargetInfo cti) {
Jeff Sharkey2b9eb892016-02-16 09:21:51 -0700863 // We're dispatching intents that might be coming from legacy apps, so
864 // don't kill ourselves.
865 StrictMode.disableDeathOnFileUriExposure();
866 try {
867 safelyStartActivityInternal(cti);
868 } finally {
869 StrictMode.enableDeathOnFileUriExposure();
870 }
871 }
872
873 private void safelyStartActivityInternal(TargetInfo cti) {
Sander Alewijnsef6545332014-10-31 12:39:02 +0000874 // If needed, show that intent is forwarded
875 // from managed profile to owner or other way around.
876 if (mProfileSwitchMessageId != -1) {
877 Toast.makeText(this, getString(mProfileSwitchMessageId), Toast.LENGTH_LONG).show();
878 }
Dianne Hackborn028ceeb2014-08-17 17:45:48 -0700879 if (!mSafeForwardingMode) {
Adam Powell24428412015-04-01 17:19:56 -0700880 if (cti.start(this, null)) {
881 onActivityStarted(cti);
882 }
Dianne Hackborn028ceeb2014-08-17 17:45:48 -0700883 return;
884 }
885 try {
Adam Powell24428412015-04-01 17:19:56 -0700886 if (cti.startAsCaller(this, null, UserHandle.USER_NULL)) {
887 onActivityStarted(cti);
888 }
Dianne Hackborn028ceeb2014-08-17 17:45:48 -0700889 } catch (RuntimeException e) {
890 String launchedFromPackage;
891 try {
Wale Ogunwale04d9cb52018-04-30 13:55:07 -0700892 launchedFromPackage = ActivityTaskManager.getService().getLaunchedFromPackage(
Dianne Hackborn028ceeb2014-08-17 17:45:48 -0700893 getActivityToken());
894 } catch (RemoteException e2) {
895 launchedFromPackage = "??";
896 }
897 Slog.wtf(TAG, "Unable to launch as uid " + mLaunchedFromUid
898 + " package " + launchedFromPackage + ", while running in "
899 + ActivityThread.currentProcessName(), e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800900 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 }
902
Alison Cichowlas3e340502018-08-07 17:15:01 -0400903
904 boolean startAsCallerImpl(Intent intent, Bundle options, boolean ignoreTargetSecurity,
905 int userId) {
906 // Pass intent to delegate chooser activity with permission token.
907 // TODO: This should move to a trampoline Activity in the system when the ChooserActivity
908 // moves into systemui
909 try {
910 // TODO: Once this is a small springboard activity, it can move off the UI process
911 // and we can move the request method to ActivityManagerInternal.
912 IBinder permissionToken = ActivityTaskManager.getService()
913 .requestStartActivityPermissionToken(getActivityToken());
914 final Intent chooserIntent = new Intent();
915 final ComponentName delegateActivity = ComponentName.unflattenFromString(
916 Resources.getSystem().getString(R.string.config_chooserActivity));
917 chooserIntent.setClassName(delegateActivity.getPackageName(),
918 delegateActivity.getClassName());
919 chooserIntent.putExtra(ActivityTaskManager.EXTRA_PERMISSION_TOKEN, permissionToken);
920
921 // TODO: These extras will change as chooser activity moves into systemui
922 chooserIntent.putExtra(Intent.EXTRA_INTENT, intent);
923 chooserIntent.putExtra(ActivityTaskManager.EXTRA_OPTIONS, options);
924 chooserIntent.putExtra(ActivityTaskManager.EXTRA_IGNORE_TARGET_SECURITY,
925 ignoreTargetSecurity);
926 chooserIntent.putExtra(Intent.EXTRA_USER_ID, userId);
Alison Cichowlas7b6f3b62018-12-07 09:06:57 -0500927 chooserIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
928 | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
Alison Cichowlas3e340502018-08-07 17:15:01 -0400929 startActivity(chooserIntent);
930 } catch (RemoteException e) {
931 Log.e(TAG, e.toString());
932 }
933 return true;
934 }
935
Adam Powell23882512016-01-29 10:21:00 -0800936 public void onActivityStarted(TargetInfo cti) {
Adam Powell0b3c1122014-10-09 12:50:14 -0700937 // Do nothing
938 }
939
Adam Powell23882512016-01-29 10:21:00 -0800940 public boolean shouldGetActivityMetadata() {
Adam Powell24428412015-04-01 17:19:56 -0700941 return false;
942 }
943
Adam Powell23882512016-01-29 10:21:00 -0800944 public boolean shouldAutoLaunchSingleChoice(TargetInfo target) {
Adam Powell39e94eb2015-09-08 17:01:49 -0700945 return true;
946 }
947
Adam Powell23882512016-01-29 10:21:00 -0800948 public void showTargetDetails(ResolveInfo ri) {
Dianne Hackborn028ceeb2014-08-17 17:45:48 -0700949 Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
Adam Powell0fc5b2b2012-07-18 18:20:29 -0700950 .setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
Adam Powell24428412015-04-01 17:19:56 -0700951 .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
Amith Yamasani203a2f42012-10-03 20:16:40 -0700952 startActivity(in);
Adam Powellc5878612012-05-04 18:42:38 -0700953 }
954
Adam Powell23882512016-01-29 10:21:00 -0800955 public ResolveListAdapter createAdapter(Context context, List<Intent> payloadIntents,
Adam Powell7d758002015-05-06 17:49:36 -0700956 Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
957 boolean filterLastUsed) {
958 return new ResolveListAdapter(context, payloadIntents, initialIntents, rList,
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800959 launchedFromUid, filterLastUsed, createListController());
960 }
961
962 @VisibleForTesting
963 protected ResolverListController createListController() {
964 return new ResolverListController(
965 this,
966 mPm,
967 getTargetIntent(),
968 getReferrerPackageName(),
969 mLaunchedFromUid);
Adam Powell88831a22014-11-20 18:17:00 -0800970 }
971
Adam Powell39e94eb2015-09-08 17:01:49 -0700972 /**
973 * Returns true if the activity is finishing and creation should halt
974 */
Adam Powell23882512016-01-29 10:21:00 -0800975 public boolean configureContentView(List<Intent> payloadIntents, Intent[] initialIntents,
Hakan Seyalioglu33550122017-01-06 19:54:43 -0800976 List<ResolveInfo> rList) {
Dianne Hackborn57dd7372015-07-27 18:11:14 -0700977 // The last argument of createAdapter is whether to do special handling
978 // of the last used choice to highlight it in the list. We need to always
979 // turn this off when running under voice interaction, since it results in
980 // a more complicated UI that the current voice interaction flow is not able
981 // to handle.
Adam Powell7d758002015-05-06 17:49:36 -0700982 mAdapter = createAdapter(this, payloadIntents, initialIntents, rList,
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800983 mLaunchedFromUid, mSupportsAlwaysUseOption && !isVoiceInteraction());
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800984 boolean rebuildCompleted = mAdapter.rebuildList();
Adam Powell7d758002015-05-06 17:49:36 -0700985
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800986 if (useLayoutWithDefault()) {
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800987 mLayoutId = R.layout.resolver_list_with_default;
Adam Powell7d758002015-05-06 17:49:36 -0700988 } else {
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800989 mLayoutId = getLayoutResource();
Adam Powell7d758002015-05-06 17:49:36 -0700990 }
Hakan Seyalioglu13405c52017-01-31 19:01:31 -0800991 setContentView(mLayoutId);
Adam Powell7d758002015-05-06 17:49:36 -0700992
Adam Powell50077352015-05-26 18:01:55 -0700993 int count = mAdapter.getUnfilteredCount();
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -0800994
995 // We only rebuild asynchronously when we have multiple elements to sort. In the case where
996 // we're already done, we can check if we should auto-launch immediately.
997 if (rebuildCompleted) {
998 if (count == 1 && mAdapter.getOtherProfile() == null) {
999 // Only one target, so we're a candidate to auto-launch!
1000 final TargetInfo target = mAdapter.targetInfoForPosition(0, false);
1001 if (shouldAutoLaunchSingleChoice(target)) {
1002 safelyStartActivity(target);
1003 mPackageMonitor.unregister();
1004 mRegistered = false;
1005 finish();
1006 return true;
1007 }
Jeff Sharkeycc2ae6b42015-09-29 13:04:46 -07001008 }
1009 }
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001010
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001011
Alan Viverette51efddb2017-04-05 10:00:01 -04001012 mAdapterView = findViewById(R.id.resolver_list);
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001013
1014 if (count == 0 && mAdapter.mPlaceholderCount == 0) {
Alan Viverette51efddb2017-04-05 10:00:01 -04001015 final TextView emptyView = findViewById(R.id.empty);
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001016 emptyView.setVisibility(View.VISIBLE);
Adam Powell7d758002015-05-06 17:49:36 -07001017 mAdapterView.setVisibility(View.GONE);
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001018 } else {
1019 mAdapterView.setVisibility(View.VISIBLE);
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001020 onPrepareAdapterView(mAdapterView, mAdapter);
Adam Powell7d758002015-05-06 17:49:36 -07001021 }
Adam Powell39e94eb2015-09-08 17:01:49 -07001022 return false;
Adam Powell7d758002015-05-06 17:49:36 -07001023 }
1024
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001025 public void onPrepareAdapterView(AbsListView adapterView, ResolveListAdapter adapter) {
Adam Powell7d758002015-05-06 17:49:36 -07001026 final boolean useHeader = adapter.hasFilteredItem();
1027 final ListView listView = adapterView instanceof ListView ? (ListView) adapterView : null;
1028
1029 adapterView.setAdapter(mAdapter);
1030
1031 final ItemClickListener listener = new ItemClickListener();
1032 adapterView.setOnItemClickListener(listener);
1033 adapterView.setOnItemLongClickListener(listener);
1034
shafik69df96322018-12-18 15:41:19 +00001035 if (mSupportsAlwaysUseOption || mUseLayoutForBrowsables) {
Adam Powell7d758002015-05-06 17:49:36 -07001036 listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE);
1037 }
1038
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001039 // In case this method is called again (due to activity recreation), avoid adding a new
1040 // header if one is already present.
1041 if (useHeader && listView != null && listView.getHeaderViewsCount() == 0) {
Adam Powell7d758002015-05-06 17:49:36 -07001042 listView.addHeaderView(LayoutInflater.from(this).inflate(
1043 R.layout.resolver_different_item_header, listView, false));
1044 }
Adam Powell24428412015-04-01 17:19:56 -07001045 }
1046
Matt Pietal26038402019-01-08 07:29:34 -05001047 /**
1048 * Configure the area above the app selection list (title, content preview, etc).
1049 */
1050 public void setHeader() {
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001051 if (mAdapter.getCount() == 0 && mAdapter.mPlaceholderCount == 0) {
Alan Viverette51efddb2017-04-05 10:00:01 -04001052 final TextView titleView = findViewById(R.id.title);
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001053 if (titleView != null) {
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001054 titleView.setVisibility(View.GONE);
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001055 }
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001056 }
1057
1058 CharSequence title = mTitle != null
1059 ? mTitle
shafik69df96322018-12-18 15:41:19 +00001060 : getTitleForAction(getTargetIntent(), mDefaultTitleResId);
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001061
1062 if (!TextUtils.isEmpty(title)) {
Alan Viverette51efddb2017-04-05 10:00:01 -04001063 final TextView titleView = findViewById(R.id.title);
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001064 if (titleView != null) {
1065 titleView.setText(title);
1066 }
1067 setTitle(title);
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001068 }
1069
Alan Viverette51efddb2017-04-05 10:00:01 -04001070 final ImageView iconView = findViewById(R.id.icon);
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001071 final DisplayResolveInfo iconInfo = mAdapter.getFilteredItem();
1072 if (iconView != null && iconInfo != null) {
1073 new LoadIconIntoViewTask(iconInfo, iconView).execute();
1074 }
1075 }
1076
shafik69df96322018-12-18 15:41:19 +00001077 private void resetButtonBar() {
1078 if (!mSupportsAlwaysUseOption && !mUseLayoutForBrowsables) {
1079 return;
1080 }
1081 final ViewGroup buttonLayout = findViewById(R.id.button_bar);
1082 if (buttonLayout != null) {
1083 buttonLayout.setVisibility(View.VISIBLE);
1084 mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
1085 mSettingsButton = (Button) buttonLayout.findViewById(R.id.button_app_settings);
1086 mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
1087
1088 if (mUseLayoutForBrowsables) {
1089 resetSettingsOrOnceButtonBar();
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001090 } else {
shafik69df96322018-12-18 15:41:19 +00001091 resetAlwaysOrOnceButtonBar();
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001092 }
shafik69df96322018-12-18 15:41:19 +00001093 } else {
1094 Log.e(TAG, "Layout unexpectedly does not have a button bar");
1095 }
1096 }
1097
1098 private void resetSettingsOrOnceButtonBar() {
1099 //unsetting always button
1100 mAlwaysButton.setVisibility(View.GONE);
1101
1102 // When the items load in, if an item was already selected,
1103 // enable the buttons
1104 if (mAdapterView != null
1105 && mAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) {
1106 mSettingsButton.setEnabled(true);
1107 mOnceButton.setEnabled(true);
1108 }
1109 }
1110
1111 private void resetAlwaysOrOnceButtonBar() {
1112 // This check needs to be made because layout with default
1113 // doesn't have a settings button
1114 if (mSettingsButton != null) {
1115 //unsetting always button
1116 mSettingsButton.setVisibility(View.GONE);
1117 mSettingsButton = null;
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001118 }
1119
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001120 if (useLayoutWithDefault()
1121 && mAdapter.getFilteredPosition() != ListView.INVALID_POSITION) {
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001122 setAlwaysButtonEnabled(true, mAdapter.getFilteredPosition(), false);
1123 mOnceButton.setEnabled(true);
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001124 return;
1125 }
1126
1127 // When the items load in, if an item was already selected, enable the buttons
1128 if (mAdapterView != null
1129 && mAdapterView.getCheckedItemPosition() != ListView.INVALID_POSITION) {
1130 setAlwaysButtonEnabled(true, mAdapterView.getCheckedItemPosition(), true);
1131 mOnceButton.setEnabled(true);
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001132 }
1133 }
1134
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001135 private boolean useLayoutWithDefault() {
1136 return mSupportsAlwaysUseOption && mAdapter.hasFilteredItem();
1137 }
1138
Adam Powellc412be62015-06-24 13:54:10 -07001139 /**
Jorim Jaggif631ef72017-02-24 13:49:47 +01001140 * If {@code retainInOnStop} is set to true, we will not finish ourselves when onStop gets
1141 * called and we are launched in a new task.
1142 */
1143 protected void setRetainInOnStop(boolean retainInOnStop) {
1144 mRetainInOnStop = retainInOnStop;
1145 }
1146
1147 /**
Adam Powellc412be62015-06-24 13:54:10 -07001148 * Check a simple match for the component of two ResolveInfos.
1149 */
1150 static boolean resolveInfoMatch(ResolveInfo lhs, ResolveInfo rhs) {
1151 return lhs == null ? rhs == null
1152 : lhs.activityInfo == null ? rhs.activityInfo == null
1153 : Objects.equals(lhs.activityInfo.name, rhs.activityInfo.name)
1154 && Objects.equals(lhs.activityInfo.packageName, rhs.activityInfo.packageName);
1155 }
1156
Adam Powell23882512016-01-29 10:21:00 -08001157 public final class DisplayResolveInfo implements TargetInfo {
Adam Powell24428412015-04-01 17:19:56 -07001158 private final ResolveInfo mResolveInfo;
1159 private final CharSequence mDisplayLabel;
1160 private Drawable mDisplayIcon;
Adam Powell00f4aad2015-09-17 13:38:16 -07001161 private Drawable mBadge;
Adam Powell24428412015-04-01 17:19:56 -07001162 private final CharSequence mExtendedInfo;
1163 private final Intent mResolvedIntent;
Adam Powell2ed547e2015-04-29 18:45:04 -07001164 private final List<Intent> mSourceIntents = new ArrayList<>();
Adam Powell23882512016-01-29 10:21:00 -08001165 private boolean mPinned;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001166
Adam Powell23882512016-01-29 10:21:00 -08001167 public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel,
Dianne Hackborneb034652009-09-07 00:49:58 -07001168 CharSequence pInfo, Intent pOrigIntent) {
Adam Powell2ed547e2015-04-29 18:45:04 -07001169 mSourceIntents.add(originalIntent);
Adam Powell24428412015-04-01 17:19:56 -07001170 mResolveInfo = pri;
1171 mDisplayLabel = pLabel;
1172 mExtendedInfo = pInfo;
1173
1174 final Intent intent = new Intent(pOrigIntent != null ? pOrigIntent :
Adam Powell2ed547e2015-04-29 18:45:04 -07001175 getReplacementIntent(pri.activityInfo, getTargetIntent()));
Adam Powell24428412015-04-01 17:19:56 -07001176 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
1177 | Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
1178 final ActivityInfo ai = mResolveInfo.activityInfo;
1179 intent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name));
1180
1181 mResolvedIntent = intent;
1182 }
1183
Adam Powell2ed547e2015-04-29 18:45:04 -07001184 private DisplayResolveInfo(DisplayResolveInfo other, Intent fillInIntent, int flags) {
1185 mSourceIntents.addAll(other.getAllSourceIntents());
1186 mResolveInfo = other.mResolveInfo;
1187 mDisplayLabel = other.mDisplayLabel;
1188 mDisplayIcon = other.mDisplayIcon;
1189 mExtendedInfo = other.mExtendedInfo;
1190 mResolvedIntent = new Intent(other.mResolvedIntent);
1191 mResolvedIntent.fillIn(fillInIntent, flags);
Adam Powell23882512016-01-29 10:21:00 -08001192 mPinned = other.mPinned;
Adam Powell2ed547e2015-04-29 18:45:04 -07001193 }
1194
Adam Powell24428412015-04-01 17:19:56 -07001195 public ResolveInfo getResolveInfo() {
1196 return mResolveInfo;
1197 }
1198
1199 public CharSequence getDisplayLabel() {
1200 return mDisplayLabel;
1201 }
1202
1203 public Drawable getDisplayIcon() {
1204 return mDisplayIcon;
1205 }
1206
Adam Powell7d758002015-05-06 17:49:36 -07001207 public Drawable getBadgeIcon() {
Adam Powell00f4aad2015-09-17 13:38:16 -07001208 // We only expose a badge if we have extended info.
1209 // The badge is a higher-priority disambiguation signal
1210 // but we don't need one if we wouldn't show extended info at all.
1211 if (TextUtils.isEmpty(getExtendedInfo())) {
1212 return null;
1213 }
1214
1215 if (mBadge == null && mResolveInfo != null && mResolveInfo.activityInfo != null
1216 && mResolveInfo.activityInfo.applicationInfo != null) {
1217 if (mResolveInfo.activityInfo.icon == 0 || mResolveInfo.activityInfo.icon
1218 == mResolveInfo.activityInfo.applicationInfo.icon) {
1219 // Badging an icon with exactly the same icon is silly.
1220 // If the activityInfo icon resid is 0 it will fall back
1221 // to the application's icon, making it a match.
1222 return null;
1223 }
1224 mBadge = mResolveInfo.activityInfo.applicationInfo.loadIcon(mPm);
1225 }
1226 return mBadge;
Adam Powell7d758002015-05-06 17:49:36 -07001227 }
1228
Adam Powell2ed547e2015-04-29 18:45:04 -07001229 @Override
Alan Viverettece5d92c2015-07-31 16:46:56 -04001230 public CharSequence getBadgeContentDescription() {
1231 return null;
1232 }
1233
1234 @Override
Adam Powell2ed547e2015-04-29 18:45:04 -07001235 public TargetInfo cloneFilledIn(Intent fillInIntent, int flags) {
1236 return new DisplayResolveInfo(this, fillInIntent, flags);
1237 }
1238
1239 @Override
1240 public List<Intent> getAllSourceIntents() {
1241 return mSourceIntents;
1242 }
1243
1244 public void addAlternateSourceIntent(Intent alt) {
1245 mSourceIntents.add(alt);
1246 }
1247
Adam Powell24428412015-04-01 17:19:56 -07001248 public void setDisplayIcon(Drawable icon) {
1249 mDisplayIcon = icon;
1250 }
1251
1252 public boolean hasDisplayIcon() {
1253 return mDisplayIcon != null;
1254 }
1255
1256 public CharSequence getExtendedInfo() {
1257 return mExtendedInfo;
1258 }
1259
1260 public Intent getResolvedIntent() {
1261 return mResolvedIntent;
1262 }
1263
1264 @Override
1265 public ComponentName getResolvedComponentName() {
1266 return new ComponentName(mResolveInfo.activityInfo.packageName,
1267 mResolveInfo.activityInfo.name);
1268 }
1269
1270 @Override
1271 public boolean start(Activity activity, Bundle options) {
1272 activity.startActivity(mResolvedIntent, options);
1273 return true;
1274 }
1275
1276 @Override
Alison Cichowlas3e340502018-08-07 17:15:01 -04001277 public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
Alison Cichowlas4691ed42018-11-13 15:59:55 -05001278
1279 if (mEnableChooserDelegate) {
1280 return activity.startAsCallerImpl(mResolvedIntent, options, false, userId);
1281 } else {
1282 activity.startActivityAsCaller(mResolvedIntent, options, null, false, userId);
1283 return true;
1284 }
Adam Powell24428412015-04-01 17:19:56 -07001285 }
1286
1287 @Override
1288 public boolean startAsUser(Activity activity, Bundle options, UserHandle user) {
1289 activity.startActivityAsUser(mResolvedIntent, options, user);
1290 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 }
Adam Powell23882512016-01-29 10:21:00 -08001292
1293 @Override
1294 public boolean isPinned() {
1295 return mPinned;
1296 }
1297
1298 public void setPinned(boolean pinned) {
1299 mPinned = pinned;
1300 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 }
1302
Adam Powell24428412015-04-01 17:19:56 -07001303 /**
1304 * A single target as represented in the chooser.
1305 */
1306 public interface TargetInfo {
1307 /**
1308 * Get the resolved intent that represents this target. Note that this may not be the
1309 * intent that will be launched by calling one of the <code>start</code> methods provided;
1310 * this is the intent that will be credited with the launch.
1311 *
1312 * @return the resolved intent for this target
1313 */
Adam Powell23882512016-01-29 10:21:00 -08001314 Intent getResolvedIntent();
Adam Powell24428412015-04-01 17:19:56 -07001315
1316 /**
1317 * Get the resolved component name that represents this target. Note that this may not
1318 * be the component that will be directly launched by calling one of the <code>start</code>
1319 * methods provided; this is the component that will be credited with the launch.
1320 *
1321 * @return the resolved ComponentName for this target
1322 */
Adam Powell23882512016-01-29 10:21:00 -08001323 ComponentName getResolvedComponentName();
Adam Powell24428412015-04-01 17:19:56 -07001324
1325 /**
1326 * Start the activity referenced by this target.
1327 *
1328 * @param activity calling Activity performing the launch
1329 * @param options ActivityOptions bundle
1330 * @return true if the start completed successfully
1331 */
Adam Powell23882512016-01-29 10:21:00 -08001332 boolean start(Activity activity, Bundle options);
Adam Powell24428412015-04-01 17:19:56 -07001333
1334 /**
1335 * Start the activity referenced by this target as if the ResolverActivity's caller
1336 * was performing the start operation.
1337 *
1338 * @param activity calling Activity (actually) performing the launch
1339 * @param options ActivityOptions bundle
1340 * @param userId userId to start as or {@link UserHandle#USER_NULL} for activity's caller
1341 * @return true if the start completed successfully
1342 */
Alison Cichowlas3e340502018-08-07 17:15:01 -04001343 boolean startAsCaller(ResolverActivity activity, Bundle options, int userId);
Adam Powell24428412015-04-01 17:19:56 -07001344
1345 /**
1346 * Start the activity referenced by this target as a given user.
1347 *
1348 * @param activity calling activity performing the launch
1349 * @param options ActivityOptions bundle
1350 * @param user handle for the user to start the activity as
1351 * @return true if the start completed successfully
1352 */
Adam Powell23882512016-01-29 10:21:00 -08001353 boolean startAsUser(Activity activity, Bundle options, UserHandle user);
Adam Powell24428412015-04-01 17:19:56 -07001354
1355 /**
1356 * Return the ResolveInfo about how and why this target matched the original query
1357 * for available targets.
1358 *
1359 * @return ResolveInfo representing this target's match
1360 */
Adam Powell23882512016-01-29 10:21:00 -08001361 ResolveInfo getResolveInfo();
Adam Powell24428412015-04-01 17:19:56 -07001362
1363 /**
1364 * Return the human-readable text label for this target.
1365 *
1366 * @return user-visible target label
1367 */
Adam Powell23882512016-01-29 10:21:00 -08001368 CharSequence getDisplayLabel();
Adam Powell24428412015-04-01 17:19:56 -07001369
1370 /**
1371 * Return any extended info for this target. This may be used to disambiguate
1372 * otherwise identical targets.
1373 *
1374 * @return human-readable disambig string or null if none present
1375 */
Adam Powell23882512016-01-29 10:21:00 -08001376 CharSequence getExtendedInfo();
Adam Powell24428412015-04-01 17:19:56 -07001377
1378 /**
1379 * @return The drawable that should be used to represent this target
1380 */
Adam Powell23882512016-01-29 10:21:00 -08001381 Drawable getDisplayIcon();
Adam Powell2ed547e2015-04-29 18:45:04 -07001382
1383 /**
Adam Powell7d758002015-05-06 17:49:36 -07001384 * @return The (small) icon to badge the target with
1385 */
Adam Powell23882512016-01-29 10:21:00 -08001386 Drawable getBadgeIcon();
Adam Powell7d758002015-05-06 17:49:36 -07001387
1388 /**
Alan Viverettece5d92c2015-07-31 16:46:56 -04001389 * @return The content description for the badge icon
1390 */
Adam Powell23882512016-01-29 10:21:00 -08001391 CharSequence getBadgeContentDescription();
Alan Viverettece5d92c2015-07-31 16:46:56 -04001392
1393 /**
Adam Powell2ed547e2015-04-29 18:45:04 -07001394 * Clone this target with the given fill-in information.
1395 */
Adam Powell23882512016-01-29 10:21:00 -08001396 TargetInfo cloneFilledIn(Intent fillInIntent, int flags);
Adam Powell2ed547e2015-04-29 18:45:04 -07001397
1398 /**
1399 * @return the list of supported source intents deduped against this single target
1400 */
Adam Powell23882512016-01-29 10:21:00 -08001401 List<Intent> getAllSourceIntents();
1402
1403 /**
1404 * @return true if this target should be pinned to the front by the request of the user
1405 */
1406 boolean isPinned();
Adam Powell24428412015-04-01 17:19:56 -07001407 }
1408
Adam Powell23882512016-01-29 10:21:00 -08001409 public class ResolveListAdapter extends BaseAdapter {
Adam Powell7d758002015-05-06 17:49:36 -07001410 private final List<Intent> mIntents;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -08001411 private final Intent[] mInitialIntents;
1412 private final List<ResolveInfo> mBaseResolveList;
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001413 protected ResolveInfo mLastChosen;
Adam Powell88831a22014-11-20 18:17:00 -08001414 private DisplayResolveInfo mOtherProfile;
Adam Powell24428412015-04-01 17:19:56 -07001415 private boolean mHasExtendedInfo;
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001416 private ResolverListController mResolverListController;
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001417 private int mPlaceholderCount;
Adam Powell24428412015-04-01 17:19:56 -07001418
1419 protected final LayoutInflater mInflater;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001420
Adam Powell2ed547e2015-04-29 18:45:04 -07001421 List<DisplayResolveInfo> mDisplayList;
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001422 List<ResolvedComponentInfo> mUnfilteredResolveList;
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -07001423
Adam Powell278902c2014-07-12 18:33:22 -07001424 private int mLastChosenPosition = -1;
1425 private boolean mFilterLastUsed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001426
Adam Powell7d758002015-05-06 17:49:36 -07001427 public ResolveListAdapter(Context context, List<Intent> payloadIntents,
1428 Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001429 boolean filterLastUsed,
1430 ResolverListController resolverListController) {
Adam Powell7d758002015-05-06 17:49:36 -07001431 mIntents = payloadIntents;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -08001432 mInitialIntents = initialIntents;
1433 mBaseResolveList = rList;
Dianne Hackborn5320eb82012-05-18 12:05:04 -07001434 mLaunchedFromUid = launchedFromUid;
Adam Powelle9414d92014-07-05 17:44:18 -07001435 mInflater = LayoutInflater.from(context);
Adam Powell2ed547e2015-04-29 18:45:04 -07001436 mDisplayList = new ArrayList<>();
Adam Powell278902c2014-07-12 18:33:22 -07001437 mFilterLastUsed = filterLastUsed;
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001438 mResolverListController = resolverListController;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -08001439 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -08001441 public void handlePackagesChanged() {
1442 rebuildList();
Esteban Talavera6de72662014-12-11 17:54:07 +00001443 if (getCount() == 0) {
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -08001444 // We no longer have any items... just finish the activity.
1445 finish();
Adam Powellc5878612012-05-04 18:42:38 -07001446 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -08001447 }
1448
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001449 public void setPlaceholderCount(int count) {
1450 mPlaceholderCount = count;
1451 }
1452
Sumir Katariadb688af2017-05-10 17:33:47 -07001453 public int getPlaceholderCount() { return mPlaceholderCount; }
1454
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001455 @Nullable
Adam Powell278902c2014-07-12 18:33:22 -07001456 public DisplayResolveInfo getFilteredItem() {
1457 if (mFilterLastUsed && mLastChosenPosition >= 0) {
1458 // Not using getItem since it offsets to dodge this position for the list
Adam Powell2ed547e2015-04-29 18:45:04 -07001459 return mDisplayList.get(mLastChosenPosition);
Adam Powell278902c2014-07-12 18:33:22 -07001460 }
1461 return null;
1462 }
1463
Adam Powell88831a22014-11-20 18:17:00 -08001464 public DisplayResolveInfo getOtherProfile() {
1465 return mOtherProfile;
1466 }
1467
Adam Powell278902c2014-07-12 18:33:22 -07001468 public int getFilteredPosition() {
1469 if (mFilterLastUsed && mLastChosenPosition >= 0) {
1470 return mLastChosenPosition;
1471 }
1472 return AbsListView.INVALID_POSITION;
1473 }
1474
1475 public boolean hasFilteredItem() {
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001476 return mFilterLastUsed && mLastChosen != null;
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -07001477 }
1478
Adam Powella182e452015-07-06 16:57:56 -07001479 public float getScore(DisplayResolveInfo target) {
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001480 return mResolverListController.getScore(target);
Adam Powella182e452015-07-06 16:57:56 -07001481 }
1482
Kang Li0cef910d2017-01-05 09:14:36 -08001483 public void updateModel(ComponentName componentName) {
1484 mResolverListController.updateModel(componentName);
1485 }
1486
Kang Li9fa2a2c2017-01-06 13:33:24 -08001487 public void updateChooserCounts(String packageName, int userId, String action) {
1488 mResolverListController.updateChooserCounts(packageName, userId, action);
1489 }
1490
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001491 /**
1492 * Rebuild the list of resolvers. In some cases some parts will need some asynchronous work
1493 * to complete.
1494 *
1495 * @return Whether or not the list building is completed.
1496 */
1497 protected boolean rebuildList() {
Adam Powell2ed547e2015-04-29 18:45:04 -07001498 List<ResolvedComponentInfo> currentResolveList = null;
Sudheer Shanka7e64e102015-01-23 10:37:45 +00001499 // Clear the value of mOtherProfile from previous call.
1500 mOtherProfile = null;
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001501 mLastChosen = null;
1502 mLastChosenPosition = -1;
Adam Powell2ed547e2015-04-29 18:45:04 -07001503 mDisplayList.clear();
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -08001504 if (mBaseResolveList != null) {
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001505 currentResolveList = mUnfilteredResolveList = new ArrayList<>();
1506 mResolverListController.addResolveListDedupe(currentResolveList,
1507 getTargetIntent(),
1508 mBaseResolveList);
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -08001509 } else {
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001510 currentResolveList = mUnfilteredResolveList =
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001511 mResolverListController.getResolversForIntent(shouldGetResolvedFilter(),
1512 shouldGetActivityMetadata(),
1513 mIntents);
1514 if (currentResolveList == null) {
1515 processSortedList(currentResolveList);
1516 return true;
Adam Powell2ed547e2015-04-29 18:45:04 -07001517 }
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001518 List<ResolvedComponentInfo> originalList =
1519 mResolverListController.filterIneligibleActivities(currentResolveList,
1520 true);
1521 if (originalList != null) {
1522 mUnfilteredResolveList = originalList;
Dianne Hackborn5320eb82012-05-18 12:05:04 -07001523 }
Jeff Hamiltond88e9aa2011-01-24 14:53:00 -06001524 }
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001525
1526 // So far we only support a single other profile at a time.
1527 // The first one we see gets special treatment.
1528 for (ResolvedComponentInfo info : currentResolveList) {
1529 if (info.getResolveInfoAt(0).targetUserId != UserHandle.USER_CURRENT) {
1530 mOtherProfile = new DisplayResolveInfo(info.getIntentAt(0),
1531 info.getResolveInfoAt(0),
1532 info.getResolveInfoAt(0).loadLabel(mPm),
1533 info.getResolveInfoAt(0).loadLabel(mPm),
1534 getReplacementIntent(info.getResolveInfoAt(0).activityInfo,
1535 info.getIntentAt(0)));
1536 currentResolveList.remove(info);
1537 break;
1538 }
1539 }
1540
1541 if (mOtherProfile == null) {
1542 try {
1543 mLastChosen = mResolverListController.getLastChosen();
1544 } catch (RemoteException re) {
1545 Log.d(TAG, "Error calling getLastChosenActivity\n" + re);
1546 }
1547 }
1548
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001549 int N;
You Kim43a5070e2012-11-21 23:23:45 +09001550 if ((currentResolveList != null) && ((N = currentResolveList.size()) > 0)) {
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001551 // We only care about fixing the unfilteredList if the current resolve list and
1552 // current resolve list are currently the same.
1553 List<ResolvedComponentInfo> originalList =
1554 mResolverListController.filterLowPriority(currentResolveList,
1555 mUnfilteredResolveList == currentResolveList);
1556 if (originalList != null) {
1557 mUnfilteredResolveList = originalList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 }
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001559
Hakan Seyalioglu873cbfd2017-02-21 19:23:43 -08001560 if (currentResolveList.size() > 1) {
Sumir Katariadb688af2017-05-10 17:33:47 -07001561 int placeholderCount = currentResolveList.size();
1562 if (useLayoutWithDefault()) {
1563 --placeholderCount;
1564 }
1565 setPlaceholderCount(placeholderCount);
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001566 AsyncTask<List<ResolvedComponentInfo>,
1567 Void,
1568 List<ResolvedComponentInfo>> sortingTask =
1569 new AsyncTask<List<ResolvedComponentInfo>,
1570 Void,
1571 List<ResolvedComponentInfo>>() {
1572 @Override
1573 protected List<ResolvedComponentInfo> doInBackground(
1574 List<ResolvedComponentInfo>... params) {
1575 mResolverListController.sort(params[0]);
1576 return params[0];
1577 }
1578
1579 @Override
1580 protected void onPostExecute(List<ResolvedComponentInfo> sortedComponents) {
1581 processSortedList(sortedComponents);
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001582 if (mProfileView != null) {
1583 bindProfileView();
1584 }
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001585 notifyDataSetChanged();
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001586 }
1587 };
1588 sortingTask.execute(currentResolveList);
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001589 postListReadyRunnable();
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001590 return false;
1591 } else {
1592 processSortedList(currentResolveList);
1593 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001594 }
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001595 } else {
1596 processSortedList(currentResolveList);
1597 return true;
1598 }
1599 }
1600
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001601 private void processSortedList(List<ResolvedComponentInfo> sortedComponents) {
1602 int N;
1603 if (sortedComponents != null && (N = sortedComponents.size()) != 0) {
Dianne Hackborneb034652009-09-07 00:49:58 -07001604 // First put the initial items at the top.
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -08001605 if (mInitialIntents != null) {
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001606 for (int i = 0; i < mInitialIntents.length; i++) {
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -08001607 Intent ii = mInitialIntents[i];
Dianne Hackborneb034652009-09-07 00:49:58 -07001608 if (ii == null) {
1609 continue;
1610 }
1611 ActivityInfo ai = ii.resolveActivityInfo(
1612 getPackageManager(), 0);
1613 if (ai == null) {
Adam Powell09a65602014-07-20 16:23:14 -07001614 Log.w(TAG, "No activity found for " + ii);
Dianne Hackborneb034652009-09-07 00:49:58 -07001615 continue;
1616 }
1617 ResolveInfo ri = new ResolveInfo();
1618 ri.activityInfo = ai;
Nicolas Prevot1a815922014-10-10 16:22:38 +01001619 UserManager userManager =
1620 (UserManager) getSystemService(Context.USER_SERVICE);
Dianne Hackborneb034652009-09-07 00:49:58 -07001621 if (ii instanceof LabeledIntent) {
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001622 LabeledIntent li = (LabeledIntent) ii;
Dianne Hackborneb034652009-09-07 00:49:58 -07001623 ri.resolvePackageName = li.getSourcePackage();
1624 ri.labelRes = li.getLabelResource();
1625 ri.nonLocalizedLabel = li.getNonLocalizedLabel();
1626 ri.icon = li.getIconResource();
Sudheer Shanka9ded7602015-05-19 21:17:25 +01001627 ri.iconResourceId = ri.icon;
1628 }
1629 if (userManager.isManagedProfile()) {
1630 ri.noResourceId = true;
1631 ri.icon = 0;
Dianne Hackborneb034652009-09-07 00:49:58 -07001632 }
Adam Powell2ed547e2015-04-29 18:45:04 -07001633 addResolveInfo(new DisplayResolveInfo(ii, ri,
Dianne Hackborneb034652009-09-07 00:49:58 -07001634 ri.loadLabel(getPackageManager()), null, ii));
1635 }
1636 }
You Kim43a5070e2012-11-21 23:23:45 +09001637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001638 // Check for applications with same name and use application name or
1639 // package name if necessary
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001640 ResolvedComponentInfo rci0 = sortedComponents.get(0);
1641 ResolveInfo r0 = rci0.getResolveInfoAt(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001642 int start = 0;
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001643 CharSequence r0Label = r0.loadLabel(mPm);
Adam Powell24428412015-04-01 17:19:56 -07001644 mHasExtendedInfo = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 for (int i = 1; i < N; i++) {
1646 if (r0Label == null) {
1647 r0Label = r0.activityInfo.packageName;
1648 }
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001649 ResolvedComponentInfo rci = sortedComponents.get(i);
Adam Powell2ed547e2015-04-29 18:45:04 -07001650 ResolveInfo ri = rci.getResolveInfoAt(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001651 CharSequence riLabel = ri.loadLabel(mPm);
1652 if (riLabel == null) {
1653 riLabel = ri.activityInfo.packageName;
1654 }
1655 if (riLabel.equals(r0Label)) {
1656 continue;
1657 }
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001658 processGroup(sortedComponents, start, (i - 1), rci0, r0Label);
Adam Powell2ed547e2015-04-29 18:45:04 -07001659 rci0 = rci;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 r0 = ri;
1661 r0Label = riLabel;
1662 start = i;
1663 }
1664 // Process last group
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001665 processGroup(sortedComponents, start, (N - 1), rci0, r0Label);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001666 }
Hakan Seyalioglu33550122017-01-06 19:54:43 -08001667
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001668 postListReadyRunnable();
1669 }
1670
1671 /**
1672 * Some necessary methods for creating the list are initiated in onCreate and will also
1673 * determine the layout known. We therefore can't update the UI inline and post to the
1674 * handler thread to update after the current task is finished.
1675 */
1676 private void postListReadyRunnable() {
1677 if (mPostListReadyRunnable == null) {
1678 mPostListReadyRunnable = new Runnable() {
1679 @Override
1680 public void run() {
Matt Pietal26038402019-01-08 07:29:34 -05001681 setHeader();
shafik69df96322018-12-18 15:41:19 +00001682 resetButtonBar();
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001683 onListRebuilt();
1684 mPostListReadyRunnable = null;
1685 }
1686 };
1687 getMainThreadHandler().post(mPostListReadyRunnable);
1688 }
Adam Powell24428412015-04-01 17:19:56 -07001689 }
1690
1691 public void onListRebuilt() {
Xiaohui Chen393c8012017-02-14 14:55:07 -08001692 int count = getUnfilteredCount();
1693 if (count == 1 && getOtherProfile() == null) {
1694 // Only one target, so we're a candidate to auto-launch!
1695 final TargetInfo target = targetInfoForPosition(0, false);
1696 if (shouldAutoLaunchSingleChoice(target)) {
1697 safelyStartActivity(target);
1698 finish();
1699 }
1700 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001701 }
1702
Adam Powellc6d5e3a2015-04-23 12:22:20 -07001703 public boolean shouldGetResolvedFilter() {
1704 return mFilterLastUsed;
1705 }
1706
Adam Powell2ed547e2015-04-29 18:45:04 -07001707 private void processGroup(List<ResolvedComponentInfo> rList, int start, int end,
1708 ResolvedComponentInfo ro, CharSequence roLabel) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001709 // Process labels from start to i
1710 int num = end - start+1;
1711 if (num == 1) {
1712 // No duplicate labels. Use label for entry at start
Adam Powell2ed547e2015-04-29 18:45:04 -07001713 addResolveInfoWithAlternates(ro, null, roLabel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001714 } else {
Adam Powell24428412015-04-01 17:19:56 -07001715 mHasExtendedInfo = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 boolean usePkg = false;
Adam Powell00f4aad2015-09-17 13:38:16 -07001717 final ApplicationInfo ai = ro.getResolveInfoAt(0).activityInfo.applicationInfo;
1718 final CharSequence startApp = ai.loadLabel(mPm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001719 if (startApp == null) {
1720 usePkg = true;
1721 }
1722 if (!usePkg) {
1723 // Use HashSet to track duplicates
1724 HashSet<CharSequence> duplicates =
1725 new HashSet<CharSequence>();
1726 duplicates.add(startApp);
1727 for (int j = start+1; j <= end ; j++) {
Adam Powell2ed547e2015-04-29 18:45:04 -07001728 ResolveInfo jRi = rList.get(j).getResolveInfoAt(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001729 CharSequence jApp = jRi.activityInfo.applicationInfo.loadLabel(mPm);
1730 if ( (jApp == null) || (duplicates.contains(jApp))) {
1731 usePkg = true;
1732 break;
1733 } else {
1734 duplicates.add(jApp);
1735 }
1736 }
1737 // Clear HashSet for later use
1738 duplicates.clear();
1739 }
1740 for (int k = start; k <= end; k++) {
Adam Powell2ed547e2015-04-29 18:45:04 -07001741 final ResolvedComponentInfo rci = rList.get(k);
1742 final ResolveInfo add = rci.getResolveInfoAt(0);
1743 final CharSequence extraInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001744 if (usePkg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 // Use package name for all entries from start to end-1
Adam Powell2ed547e2015-04-29 18:45:04 -07001746 extraInfo = add.activityInfo.packageName;
1747 } else {
1748 // Use application name for all entries from start to end-1
1749 extraInfo = add.activityInfo.applicationInfo.loadLabel(mPm);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 }
Adam Powell2ed547e2015-04-29 18:45:04 -07001751 addResolveInfoWithAlternates(rci, extraInfo, roLabel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 }
1753 }
1754 }
1755
Adam Powell2ed547e2015-04-29 18:45:04 -07001756 private void addResolveInfoWithAlternates(ResolvedComponentInfo rci,
1757 CharSequence extraInfo, CharSequence roLabel) {
1758 final int count = rci.getCount();
1759 final Intent intent = rci.getIntentAt(0);
1760 final ResolveInfo add = rci.getResolveInfoAt(0);
1761 final Intent replaceIntent = getReplacementIntent(add.activityInfo, intent);
1762 final DisplayResolveInfo dri = new DisplayResolveInfo(intent, add, roLabel,
1763 extraInfo, replaceIntent);
Adam Powell23882512016-01-29 10:21:00 -08001764 dri.setPinned(rci.isPinned());
Adam Powell2ed547e2015-04-29 18:45:04 -07001765 addResolveInfo(dri);
1766 if (replaceIntent == intent) {
1767 // Only add alternates if we didn't get a specific replacement from
1768 // the caller. If we have one it trumps potential alternates.
1769 for (int i = 1, N = count; i < N; i++) {
1770 final Intent altIntent = rci.getIntentAt(i);
1771 dri.addAlternateSourceIntent(altIntent);
1772 }
1773 }
1774 updateLastChosenPosition(add);
1775 }
1776
Esteban Talavera6de72662014-12-11 17:54:07 +00001777 private void updateLastChosenPosition(ResolveInfo info) {
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001778 // If another profile is present, ignore the last chosen entry.
1779 if (mOtherProfile != null) {
1780 mLastChosenPosition = -1;
1781 return;
1782 }
Esteban Talavera6de72662014-12-11 17:54:07 +00001783 if (mLastChosen != null
1784 && mLastChosen.activityInfo.packageName.equals(info.activityInfo.packageName)
1785 && mLastChosen.activityInfo.name.equals(info.activityInfo.name)) {
Adam Powell2ed547e2015-04-29 18:45:04 -07001786 mLastChosenPosition = mDisplayList.size() - 1;
Esteban Talavera6de72662014-12-11 17:54:07 +00001787 }
1788 }
1789
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08001790 // We assume that at this point we've already filtered out the only intent for a different
1791 // targetUserId which we're going to use.
Adam Powell88831a22014-11-20 18:17:00 -08001792 private void addResolveInfo(DisplayResolveInfo dri) {
Kang Li6afa4f22017-06-23 12:54:38 -07001793 if (dri != null && dri.mResolveInfo != null
1794 && dri.mResolveInfo.targetUserId == UserHandle.USER_CURRENT) {
1795 // Checks if this info is already listed in display.
1796 for (DisplayResolveInfo existingInfo : mDisplayList) {
1797 if (resolveInfoMatch(dri.mResolveInfo, existingInfo.mResolveInfo)) {
1798 return;
1799 }
1800 }
Adam Powell2ed547e2015-04-29 18:45:04 -07001801 mDisplayList.add(dri);
Adam Powell88831a22014-11-20 18:17:00 -08001802 }
1803 }
1804
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001805 @Nullable
Adam Powell278902c2014-07-12 18:33:22 -07001806 public ResolveInfo resolveInfoForPosition(int position, boolean filtered) {
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001807 TargetInfo target = targetInfoForPosition(position, filtered);
1808 if (target != null) {
1809 return target.getResolveInfo();
1810 }
1811 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001812 }
1813
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001814 @Nullable
Adam Powell24428412015-04-01 17:19:56 -07001815 public TargetInfo targetInfoForPosition(int position, boolean filtered) {
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001816 if (filtered) {
1817 return getItem(position);
1818 }
1819 if (mDisplayList.size() > position) {
1820 return mDisplayList.get(position);
1821 }
1822 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823 }
1824
1825 public int getCount() {
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001826 int totalSize = mDisplayList == null || mDisplayList.isEmpty() ? mPlaceholderCount :
1827 mDisplayList.size();
Adam Powell278902c2014-07-12 18:33:22 -07001828 if (mFilterLastUsed && mLastChosenPosition >= 0) {
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001829 totalSize--;
Adam Powell278902c2014-07-12 18:33:22 -07001830 }
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001831 return totalSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 }
1833
Adam Powell50077352015-05-26 18:01:55 -07001834 public int getUnfilteredCount() {
1835 return mDisplayList.size();
1836 }
1837
1838 public int getDisplayInfoCount() {
1839 return mDisplayList.size();
1840 }
1841
1842 public DisplayResolveInfo getDisplayInfoAt(int index) {
1843 return mDisplayList.get(index);
1844 }
1845
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001846 @Nullable
Adam Powell24428412015-04-01 17:19:56 -07001847 public TargetInfo getItem(int position) {
Adam Powell278902c2014-07-12 18:33:22 -07001848 if (mFilterLastUsed && mLastChosenPosition >= 0 && position >= mLastChosenPosition) {
1849 position++;
1850 }
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001851 if (mDisplayList.size() > position) {
1852 return mDisplayList.get(position);
1853 } else {
1854 return null;
1855 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001856 }
1857
1858 public long getItemId(int position) {
1859 return position;
1860 }
1861
Adam Powell24428412015-04-01 17:19:56 -07001862 public boolean hasExtendedInfo() {
1863 return mHasExtendedInfo;
1864 }
1865
1866 public boolean hasResolvedTarget(ResolveInfo info) {
Adam Powell2ed547e2015-04-29 18:45:04 -07001867 for (int i = 0, N = mDisplayList.size(); i < N; i++) {
Adam Powellc412be62015-06-24 13:54:10 -07001868 if (resolveInfoMatch(info, mDisplayList.get(i).getResolveInfo())) {
Adam Powell24428412015-04-01 17:19:56 -07001869 return true;
1870 }
1871 }
1872 return false;
1873 }
1874
Adam Powell23882512016-01-29 10:21:00 -08001875 public int getDisplayResolveInfoCount() {
Adam Powell2ed547e2015-04-29 18:45:04 -07001876 return mDisplayList.size();
Adam Powell24428412015-04-01 17:19:56 -07001877 }
1878
Adam Powell23882512016-01-29 10:21:00 -08001879 public DisplayResolveInfo getDisplayResolveInfo(int index) {
Adam Powell2ed547e2015-04-29 18:45:04 -07001880 // Used to query services. We only query services for primary targets, not alternates.
1881 return mDisplayList.get(index);
Adam Powell24428412015-04-01 17:19:56 -07001882 }
1883
1884 public final View getView(int position, View convertView, ViewGroup parent) {
Adam Powellfd1e93d2014-09-07 16:52:22 -07001885 View view = convertView;
1886 if (view == null) {
Adam Powell24428412015-04-01 17:19:56 -07001887 view = createView(parent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001888 }
Adam Powell7d758002015-05-06 17:49:36 -07001889 onBindView(view, getItem(position));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001890 return view;
1891 }
1892
Adam Powell7d758002015-05-06 17:49:36 -07001893 public final View createView(ViewGroup parent) {
1894 final View view = onCreateView(parent);
1895 final ViewHolder holder = new ViewHolder(view);
1896 view.setTag(holder);
1897 return view;
1898 }
1899
1900 public View onCreateView(ViewGroup parent) {
Adam Powell24428412015-04-01 17:19:56 -07001901 return mInflater.inflate(
1902 com.android.internal.R.layout.resolve_list_item, parent, false);
1903 }
1904
1905 public boolean showsExtendedInfo(TargetInfo info) {
1906 return !TextUtils.isEmpty(info.getExtendedInfo());
1907 }
1908
Adam Powell23882512016-01-29 10:21:00 -08001909 public boolean isComponentPinned(ComponentName name) {
1910 return false;
1911 }
1912
Adam Powell7d758002015-05-06 17:49:36 -07001913 public final void bindView(int position, View view) {
1914 onBindView(view, getItem(position));
1915 }
1916
1917 private void onBindView(View view, TargetInfo info) {
Adam Powell0256c6f2013-05-29 16:42:33 -07001918 final ViewHolder holder = (ViewHolder) view.getTag();
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08001919 if (info == null) {
1920 holder.icon.setImageDrawable(
1921 getDrawable(R.drawable.resolver_icon_placeholder));
1922 return;
1923 }
Adam Powell63b31692015-09-28 10:45:00 -07001924 final CharSequence label = info.getDisplayLabel();
1925 if (!TextUtils.equals(holder.text.getText(), label)) {
1926 holder.text.setText(info.getDisplayLabel());
1927 }
Adam Powell24428412015-04-01 17:19:56 -07001928 if (showsExtendedInfo(info)) {
Adam Powell0256c6f2013-05-29 16:42:33 -07001929 holder.text2.setVisibility(View.VISIBLE);
Adam Powell24428412015-04-01 17:19:56 -07001930 holder.text2.setText(info.getExtendedInfo());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001931 } else {
Adam Powell0256c6f2013-05-29 16:42:33 -07001932 holder.text2.setVisibility(View.GONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001933 }
Adam Powell24428412015-04-01 17:19:56 -07001934 if (info instanceof DisplayResolveInfo
1935 && !((DisplayResolveInfo) info).hasDisplayIcon()) {
1936 new LoadAdapterIconTask((DisplayResolveInfo) info).execute();
Dianne Hackborneb034652009-09-07 00:49:58 -07001937 }
Adam Powell24428412015-04-01 17:19:56 -07001938 holder.icon.setImageDrawable(info.getDisplayIcon());
Adam Powell7d758002015-05-06 17:49:36 -07001939 if (holder.badge != null) {
1940 final Drawable badge = info.getBadgeIcon();
1941 if (badge != null) {
1942 holder.badge.setImageDrawable(badge);
Alan Viverettece5d92c2015-07-31 16:46:56 -04001943 holder.badge.setContentDescription(info.getBadgeContentDescription());
Adam Powell7d758002015-05-06 17:49:36 -07001944 holder.badge.setVisibility(View.VISIBLE);
1945 } else {
1946 holder.badge.setVisibility(View.GONE);
1947 }
1948 }
Adam Powell0256c6f2013-05-29 16:42:33 -07001949 }
1950 }
1951
Hakan Seyalioglue1276bf2016-12-07 16:38:57 -08001952 @VisibleForTesting
1953 public static final class ResolvedComponentInfo {
Adam Powell2ed547e2015-04-29 18:45:04 -07001954 public final ComponentName name;
Adam Powell23882512016-01-29 10:21:00 -08001955 private boolean mPinned;
Adam Powell2ed547e2015-04-29 18:45:04 -07001956 private final List<Intent> mIntents = new ArrayList<>();
1957 private final List<ResolveInfo> mResolveInfos = new ArrayList<>();
1958
1959 public ResolvedComponentInfo(ComponentName name, Intent intent, ResolveInfo info) {
1960 this.name = name;
1961 add(intent, info);
1962 }
1963
1964 public void add(Intent intent, ResolveInfo info) {
1965 mIntents.add(intent);
1966 mResolveInfos.add(info);
1967 }
1968
1969 public int getCount() {
1970 return mIntents.size();
1971 }
1972
1973 public Intent getIntentAt(int index) {
1974 return index >= 0 ? mIntents.get(index) : null;
1975 }
1976
1977 public ResolveInfo getResolveInfoAt(int index) {
1978 return index >= 0 ? mResolveInfos.get(index) : null;
1979 }
1980
1981 public int findIntent(Intent intent) {
1982 for (int i = 0, N = mIntents.size(); i < N; i++) {
1983 if (intent.equals(mIntents.get(i))) {
1984 return i;
1985 }
1986 }
1987 return -1;
1988 }
1989
1990 public int findResolveInfo(ResolveInfo info) {
1991 for (int i = 0, N = mResolveInfos.size(); i < N; i++) {
1992 if (info.equals(mResolveInfos.get(i))) {
1993 return i;
1994 }
1995 }
1996 return -1;
1997 }
Adam Powell23882512016-01-29 10:21:00 -08001998
1999 public boolean isPinned() {
2000 return mPinned;
2001 }
2002
2003 public void setPinned(boolean pinned) {
2004 mPinned = pinned;
2005 }
Adam Powell2ed547e2015-04-29 18:45:04 -07002006 }
2007
Adam Powell0256c6f2013-05-29 16:42:33 -07002008 static class ViewHolder {
2009 public TextView text;
2010 public TextView text2;
2011 public ImageView icon;
Adam Powell7d758002015-05-06 17:49:36 -07002012 public ImageView badge;
Adam Powell0256c6f2013-05-29 16:42:33 -07002013
2014 public ViewHolder(View view) {
2015 text = (TextView) view.findViewById(com.android.internal.R.id.text1);
2016 text2 = (TextView) view.findViewById(com.android.internal.R.id.text2);
2017 icon = (ImageView) view.findViewById(R.id.icon);
Adam Powell7d758002015-05-06 17:49:36 -07002018 badge = (ImageView) view.findViewById(R.id.target_badge);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 }
2020 }
2021
Adam Powell7d758002015-05-06 17:49:36 -07002022 class ItemClickListener implements AdapterView.OnItemClickListener,
2023 AdapterView.OnItemLongClickListener {
2024 @Override
2025 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
2026 final ListView listView = parent instanceof ListView ? (ListView) parent : null;
2027 if (listView != null) {
2028 position -= listView.getHeaderViewsCount();
2029 }
2030 if (position < 0) {
2031 // Header views don't count.
2032 return;
2033 }
Hakan Seyalioglu23f34652017-02-03 09:38:35 -08002034 // If we're still loading, we can't yet enable the buttons.
2035 if (mAdapter.resolveInfoForPosition(position, true) == null) {
2036 return;
2037 }
2038
Adam Powell7d758002015-05-06 17:49:36 -07002039 final int checkedPos = mAdapterView.getCheckedItemPosition();
2040 final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
Hakan Seyalioglu13405c52017-01-31 19:01:31 -08002041 if (!useLayoutWithDefault()
Ruchi Kandoi65d76c12017-08-18 13:05:39 -07002042 && (!hasValidSelection || mLastSelected != checkedPos)
shafik69df96322018-12-18 15:41:19 +00002043 && (mAlwaysButton != null || mSettingsButton != null)) {
2044 if (mSettingsButton != null) {
2045 // this implies that the layout for browsables is being used
2046 mSettingsButton.setEnabled(true);
2047 } else {
2048 // this implies that mAlwaysButton != null
2049 setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
2050 }
Adam Powell7d758002015-05-06 17:49:36 -07002051 mOnceButton.setEnabled(hasValidSelection);
2052 if (hasValidSelection) {
2053 mAdapterView.smoothScrollToPosition(checkedPos);
2054 }
2055 mLastSelected = checkedPos;
2056 } else {
2057 startSelected(position, false, true);
2058 }
2059 }
Adam Powell2d809622012-03-22 15:24:43 -07002060
2061 @Override
2062 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Adam Powell7d758002015-05-06 17:49:36 -07002063 final ListView listView = parent instanceof ListView ? (ListView) parent : null;
2064 if (listView != null) {
2065 position -= listView.getHeaderViewsCount();
Adam Powell24428412015-04-01 17:19:56 -07002066 }
Adam Powellfd1e93d2014-09-07 16:52:22 -07002067 if (position < 0) {
2068 // Header views don't count.
2069 return false;
2070 }
Adam Powell278902c2014-07-12 18:33:22 -07002071 ResolveInfo ri = mAdapter.resolveInfoForPosition(position, true);
Adam Powell23882512016-01-29 10:21:00 -08002072 showTargetDetails(ri);
Adam Powell2d809622012-03-22 15:24:43 -07002073 return true;
2074 }
2075
2076 }
Adam Powell0256c6f2013-05-29 16:42:33 -07002077
Adam Powell24428412015-04-01 17:19:56 -07002078 abstract class LoadIconTask extends AsyncTask<Void, Void, Drawable> {
2079 protected final DisplayResolveInfo mDisplayResolveInfo;
2080 private final ResolveInfo mResolveInfo;
2081
2082 public LoadIconTask(DisplayResolveInfo dri) {
2083 mDisplayResolveInfo = dri;
2084 mResolveInfo = dri.getResolveInfo();
Adam Powell0256c6f2013-05-29 16:42:33 -07002085 }
2086
2087 @Override
Adam Powell24428412015-04-01 17:19:56 -07002088 protected Drawable doInBackground(Void... params) {
2089 return loadIconForResolveInfo(mResolveInfo);
2090 }
2091
2092 @Override
2093 protected void onPostExecute(Drawable d) {
2094 mDisplayResolveInfo.setDisplayIcon(d);
2095 }
2096 }
2097
2098 class LoadAdapterIconTask extends LoadIconTask {
2099 public LoadAdapterIconTask(DisplayResolveInfo dri) {
2100 super(dri);
2101 }
2102
2103 @Override
2104 protected void onPostExecute(Drawable d) {
2105 super.onPostExecute(d);
2106 if (mProfileView != null && mAdapter.getOtherProfile() == mDisplayResolveInfo) {
Adam Powell88831a22014-11-20 18:17:00 -08002107 bindProfileView();
2108 }
Adam Powell0256c6f2013-05-29 16:42:33 -07002109 mAdapter.notifyDataSetChanged();
2110 }
2111 }
Adam Powell278902c2014-07-12 18:33:22 -07002112
Adam Powell24428412015-04-01 17:19:56 -07002113 class LoadIconIntoViewTask extends LoadIconTask {
2114 private final ImageView mTargetView;
Adam Powell278902c2014-07-12 18:33:22 -07002115
Adam Powell24428412015-04-01 17:19:56 -07002116 public LoadIconIntoViewTask(DisplayResolveInfo dri, ImageView target) {
2117 super(dri);
Adam Powell278902c2014-07-12 18:33:22 -07002118 mTargetView = target;
2119 }
2120
2121 @Override
Adam Powell24428412015-04-01 17:19:56 -07002122 protected void onPostExecute(Drawable d) {
2123 super.onPostExecute(d);
2124 mTargetView.setImageDrawable(d);
Adam Powell278902c2014-07-12 18:33:22 -07002125 }
2126 }
Adam Powell09a65602014-07-20 16:23:14 -07002127
Dianne Hackbornec452d92014-11-11 17:16:56 -08002128 static final boolean isSpecificUriMatch(int match) {
2129 match = match&IntentFilter.MATCH_CATEGORY_MASK;
2130 return match >= IntentFilter.MATCH_CATEGORY_HOST
2131 && match <= IntentFilter.MATCH_CATEGORY_PATH;
2132 }
2133
Adam Powell4c470d62015-06-19 17:46:17 -07002134 static class PickTargetOptionRequest extends PickOptionRequest {
2135 public PickTargetOptionRequest(@Nullable Prompt prompt, Option[] options,
2136 @Nullable Bundle extras) {
2137 super(prompt, options, extras);
2138 }
2139
2140 @Override
2141 public void onCancel() {
2142 super.onCancel();
2143 final ResolverActivity ra = (ResolverActivity) getActivity();
2144 if (ra != null) {
2145 ra.mPickOptionRequest = null;
2146 ra.finish();
2147 }
2148 }
2149
2150 @Override
2151 public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) {
2152 super.onPickOptionResult(finished, selections, result);
2153 if (selections.length != 1) {
2154 // TODO In a better world we would filter the UI presented here and let the
2155 // user refine. Maybe later.
2156 return;
2157 }
2158
2159 final ResolverActivity ra = (ResolverActivity) getActivity();
2160 if (ra != null) {
2161 final TargetInfo ti = ra.mAdapter.getItem(selections[0].getIndex());
2162 if (ra.onTargetSelected(ti, false)) {
2163 ra.mPickOptionRequest = null;
2164 ra.finish();
2165 }
2166 }
2167 }
2168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002169}