blob: 76ce76584cc5d8b17561f9ba3ec8446a4787e047 [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
Adam Powelle9414d92014-07-05 17:44:18 -070019import android.app.Activity;
Adam Powell0256c6f2013-05-29 16:42:33 -070020import android.os.AsyncTask;
Adam Powell278902c2014-07-12 18:33:22 -070021import android.util.ArrayMap;
22import android.widget.AbsListView;
Adam Powelle9414d92014-07-05 17:44:18 -070023import android.widget.GridView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import com.android.internal.R;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -080025import com.android.internal.content.PackageMonitor;
26
Adam Powellc5878612012-05-04 18:42:38 -070027import android.app.ActivityManager;
Dianne Hackborn5320eb82012-05-18 12:05:04 -070028import android.app.ActivityManagerNative;
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -070029import android.app.AppGlobals;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.content.ComponentName;
31import android.content.Context;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.content.Intent;
33import android.content.IntentFilter;
34import android.content.pm.ActivityInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -070035import android.content.pm.LabeledIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.content.pm.PackageManager;
Adam Powellc5878612012-05-04 18:42:38 -070037import android.content.pm.PackageManager.NameNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.content.pm.ResolveInfo;
Adam Powellc5878612012-05-04 18:42:38 -070039import android.content.res.Resources;
Dianne Hackborneb034652009-09-07 00:49:58 -070040import android.graphics.drawable.Drawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.net.Uri;
42import android.os.Bundle;
43import android.os.PatternMatcher;
Dianne Hackborn5320eb82012-05-18 12:05:04 -070044import android.os.RemoteException;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070045import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.util.Log;
Adam Powell2d809622012-03-22 15:24:43 -070047import android.view.LayoutInflater;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.view.View;
49import android.view.ViewGroup;
Adam Powell2d809622012-03-22 15:24:43 -070050import android.widget.AdapterView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.widget.BaseAdapter;
Adam Powellc5878612012-05-04 18:42:38 -070052import android.widget.Button;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.widget.ImageView;
Adam Powell2d809622012-03-22 15:24:43 -070054import android.widget.ListView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.widget.TextView;
Adam Powell4f6c2052014-07-07 18:49:10 -070056import com.android.internal.widget.ResolverDrawerLayout;
Adam Powell2d809622012-03-22 15:24:43 -070057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import java.util.ArrayList;
59import java.util.Collections;
60import java.util.HashSet;
61import java.util.Iterator;
62import java.util.List;
63import java.util.Set;
64
65/**
66 * This activity is displayed when the system attempts to start an Intent for
67 * which there is more than one matching activity, allowing the user to decide
68 * which to go to. It is not normally used directly by application developers.
69 */
Adam Powelle9414d92014-07-05 17:44:18 -070070public class ResolverActivity extends Activity implements AdapterView.OnItemClickListener {
Adam Powellc5878612012-05-04 18:42:38 -070071 private static final String TAG = "ResolverActivity";
Adam Powelle9414d92014-07-05 17:44:18 -070072 private static final boolean DEBUG = true;
Adam Powellc5878612012-05-04 18:42:38 -070073
Dianne Hackborn5320eb82012-05-18 12:05:04 -070074 private int mLaunchedFromUid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075 private ResolveListAdapter mAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076 private PackageManager mPm;
Adam Powellc5878612012-05-04 18:42:38 -070077 private boolean mAlwaysUseOption;
78 private boolean mShowExtended;
Adam Powelle9414d92014-07-05 17:44:18 -070079 private GridView mGridView;
Adam Powellc5878612012-05-04 18:42:38 -070080 private Button mAlwaysButton;
81 private Button mOnceButton;
82 private int mIconDpi;
83 private int mIconSize;
Adam Powell589e6f92012-05-06 20:52:38 -070084 private int mMaxColumns;
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -070085 private int mLastSelected = ListView.INVALID_POSITION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086
Dianne Hackbornd44713a2012-04-30 16:34:46 -070087 private boolean mRegistered;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -080088 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
89 @Override public void onSomePackagesChanged() {
90 mAdapter.handlePackagesChanged();
91 }
92 };
93
Adam Powell278902c2014-07-12 18:33:22 -070094 private enum ActionTitle {
95 VIEW(Intent.ACTION_VIEW,
96 com.android.internal.R.string.whichViewApplication,
97 com.android.internal.R.string.whichViewApplicationNamed),
98 EDIT(Intent.ACTION_EDIT,
99 com.android.internal.R.string.whichEditApplication,
100 com.android.internal.R.string.whichEditApplicationNamed),
101 SEND(Intent.ACTION_SEND,
102 com.android.internal.R.string.whichSendApplication,
103 com.android.internal.R.string.whichSendApplicationNamed),
104 SENDTO(Intent.ACTION_SENDTO,
105 com.android.internal.R.string.whichSendApplication,
106 com.android.internal.R.string.whichSendApplicationNamed),
107 SEND_MULTIPLE(Intent.ACTION_SEND_MULTIPLE,
108 com.android.internal.R.string.whichSendApplication,
109 com.android.internal.R.string.whichSendApplicationNamed),
110 DEFAULT(null,
111 com.android.internal.R.string.whichApplication,
112 com.android.internal.R.string.whichApplicationNamed);
113
114 public final String action;
115 public final int titleRes;
116 public final int namedTitleRes;
117
118 ActionTitle(String action, int titleRes, int namedTitleRes) {
119 this.action = action;
120 this.titleRes = titleRes;
121 this.namedTitleRes = namedTitleRes;
122 }
123
124 public static ActionTitle forAction(String action) {
125 for (ActionTitle title : values()) {
126 if (action != null && action.equals(title.action)) {
127 return title;
128 }
129 }
130 return DEFAULT;
131 }
132 }
133
Dianne Hackborn905577f2011-09-07 18:31:28 -0700134 private Intent makeMyIntent() {
135 Intent intent = new Intent(getIntent());
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700136 intent.setComponent(null);
Dianne Hackborn905577f2011-09-07 18:31:28 -0700137 // The resolver activity is set to be hidden from recent tasks.
138 // we don't want this attribute to be propagated to the next activity
139 // being launched. Note that if the original Intent also had this
140 // flag set, we are now losing it. That should be a very rare case
141 // and we can live with this.
142 intent.setFlags(intent.getFlags()&~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
143 return intent;
144 }
145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 @Override
147 protected void onCreate(Bundle savedInstanceState) {
Christopher Tateb72b3632013-09-30 17:50:32 -0700148 // Use a specialized prompt when we're handling the 'Home' app startActivity()
149 final int titleResource;
150 final Intent intent = makeMyIntent();
151 final Set<String> categories = intent.getCategories();
152 if (Intent.ACTION_MAIN.equals(intent.getAction())
153 && categories != null
154 && categories.size() == 1
155 && categories.contains(Intent.CATEGORY_HOME)) {
156 titleResource = com.android.internal.R.string.whichHomeApplication;
157 } else {
Adam Powell278902c2014-07-12 18:33:22 -0700158 titleResource = 0;
Christopher Tateb72b3632013-09-30 17:50:32 -0700159 }
160
Adam Powell278902c2014-07-12 18:33:22 -0700161 onCreate(savedInstanceState, intent,
162 titleResource != 0 ? getResources().getText(titleResource) : null, titleResource,
Jeff Hamiltond88e9aa2011-01-24 14:53:00 -0600163 null, null, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164 }
165
Adam Powell278902c2014-07-12 18:33:22 -0700166 /**
167 * Compatibility version for other bundled services that use this ocerload without
168 * a default title resource
169 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 protected void onCreate(Bundle savedInstanceState, Intent intent,
Adam Powell278902c2014-07-12 18:33:22 -0700171 CharSequence title, Intent[] initialIntents,
172 List<ResolveInfo> rList, boolean alwaysUseOption) {
173 onCreate(savedInstanceState, intent, title, initialIntents, rList, alwaysUseOption);
174 }
175
176 protected void onCreate(Bundle savedInstanceState, Intent intent,
177 CharSequence title, int defaultTitleRes, Intent[] initialIntents,
178 List<ResolveInfo> rList, boolean alwaysUseOption) {
Adam Powelle9414d92014-07-05 17:44:18 -0700179 setTheme(R.style.Theme_DeviceDefault_Resolver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 super.onCreate(savedInstanceState);
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700181 try {
182 mLaunchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
183 getActivityToken());
184 } catch (RemoteException e) {
185 mLaunchedFromUid = -1;
186 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 mPm = getPackageManager();
Adam Powell589e6f92012-05-06 20:52:38 -0700188 mMaxColumns = getResources().getInteger(R.integer.config_maxResolverActivityColumns);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700190 mPackageMonitor.register(this, getMainLooper(), false);
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700191 mRegistered = true;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800192
Adam Powellc5878612012-05-04 18:42:38 -0700193 final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
194 mIconDpi = am.getLauncherLargeIconDensity();
195 mIconSize = am.getLauncherLargeIconSize();
196
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700197 mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList,
Adam Powell278902c2014-07-12 18:33:22 -0700198 mLaunchedFromUid, alwaysUseOption);
199
200 final int layoutId;
201 if (mAdapter.hasFilteredItem()) {
202 layoutId = R.layout.resolver_list_with_default;
203 alwaysUseOption = false;
204 } else {
205 layoutId = R.layout.resolver_list;
206 }
207 mAlwaysUseOption = alwaysUseOption;
208
Mike Lockwood02eb8742011-02-27 09:10:37 -0800209 int count = mAdapter.getCount();
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700210 if (mLaunchedFromUid < 0 || UserHandle.isIsolated(mLaunchedFromUid)) {
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700211 // Gulp!
212 finish();
213 return;
214 } else if (count > 1) {
Adam Powell278902c2014-07-12 18:33:22 -0700215 setContentView(layoutId);
Adam Powelle9414d92014-07-05 17:44:18 -0700216 mGridView = (GridView) findViewById(R.id.resolver_list);
217 mGridView.setAdapter(mAdapter);
218 mGridView.setOnItemClickListener(this);
219 mGridView.setOnItemLongClickListener(new ItemLongClickListener());
Adam Powellc5878612012-05-04 18:42:38 -0700220
221 if (alwaysUseOption) {
Adam Powelle9414d92014-07-05 17:44:18 -0700222 mGridView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
Adam Powellc5878612012-05-04 18:42:38 -0700223 }
Adam Powelle9414d92014-07-05 17:44:18 -0700224
225 resizeGrid();
Mike Lockwood02eb8742011-02-27 09:10:37 -0800226 } else if (count == 1) {
Adam Powell278902c2014-07-12 18:33:22 -0700227 startActivity(mAdapter.intentForPosition(0, false));
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700228 mPackageMonitor.unregister();
229 mRegistered = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 finish();
231 return;
232 } else {
Adam Powelle9414d92014-07-05 17:44:18 -0700233 setContentView(R.layout.resolver_list);
234
235 final TextView empty = (TextView) findViewById(R.id.empty);
236 empty.setVisibility(View.VISIBLE);
237
238 mGridView = (GridView) findViewById(R.id.resolver_list);
239 mGridView.setVisibility(View.GONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 }
241
Adam Powell4f6c2052014-07-07 18:49:10 -0700242 final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel);
243 if (rdl != null) {
244 rdl.setOnClickOutsideListener(new View.OnClickListener() {
245 @Override
246 public void onClick(View v) {
247 finish();
248 }
249 });
250 }
251
Adam Powelle9414d92014-07-05 17:44:18 -0700252 final TextView titleView = (TextView) findViewById(R.id.title);
253 if (titleView != null) {
Adam Powell278902c2014-07-12 18:33:22 -0700254 if (title == null) {
255 title = getTitleForAction(intent.getAction(), defaultTitleRes);
256 }
Adam Powelle9414d92014-07-05 17:44:18 -0700257 titleView.setText(title);
258 }
Adam Powell2d809622012-03-22 15:24:43 -0700259
Adam Powell278902c2014-07-12 18:33:22 -0700260 final ImageView iconView = (ImageView) findViewById(R.id.icon);
261 final DisplayResolveInfo iconInfo = mAdapter.getFilteredItem();
262 if (iconView != null && iconInfo != null) {
263 new LoadIconIntoViewTask(iconView).execute(iconInfo);
264 }
265
266 if (alwaysUseOption || mAdapter.hasFilteredItem()) {
Adam Powellc5878612012-05-04 18:42:38 -0700267 final ViewGroup buttonLayout = (ViewGroup) findViewById(R.id.button_bar);
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700268 if (buttonLayout != null) {
269 buttonLayout.setVisibility(View.VISIBLE);
270 mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
271 mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
272 } else {
273 mAlwaysUseOption = false;
274 }
Adam Powell278902c2014-07-12 18:33:22 -0700275 }
276
277 if (mAdapter.hasFilteredItem()) {
278 setAlwaysButtonEnabled(true, mAdapter.getFilteredPosition(), false);
279 mOnceButton.setEnabled(true);
280 }
281 }
282
283 protected CharSequence getTitleForAction(String action, int defaultTitleRes) {
284 final ActionTitle title = ActionTitle.forAction(action);
285 final boolean named = mAdapter.hasFilteredItem();
286 if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) {
287 return getString(defaultTitleRes);
288 } else {
289 return named ? getString(title.namedTitleRes, mAdapter.getFilteredItem().displayLabel) :
290 getString(title.titleRes);
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700291 }
Adam Powellc5878612012-05-04 18:42:38 -0700292 }
293
Adam Powelle9414d92014-07-05 17:44:18 -0700294 void resizeGrid() {
295 final int itemCount = mAdapter.getCount();
296 mGridView.setNumColumns(Math.min(itemCount, mMaxColumns));
297 }
298
299 void dismiss() {
300 if (!isFinishing()) {
301 finish();
302 }
303 }
304
Adam Powellc5878612012-05-04 18:42:38 -0700305 Drawable getIcon(Resources res, int resId) {
306 Drawable result;
307 try {
308 result = res.getDrawableForDensity(resId, mIconDpi);
309 } catch (Resources.NotFoundException e) {
310 result = null;
311 }
312
313 return result;
314 }
315
316 Drawable loadIconForResolveInfo(ResolveInfo ri) {
317 Drawable dr;
318 try {
319 if (ri.resolvePackageName != null && ri.icon != 0) {
320 dr = getIcon(mPm.getResourcesForApplication(ri.resolvePackageName), ri.icon);
321 if (dr != null) {
322 return dr;
323 }
324 }
325 final int iconRes = ri.getIconResource();
326 if (iconRes != 0) {
327 dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.packageName), iconRes);
328 if (dr != null) {
329 return dr;
330 }
331 }
332 } catch (NameNotFoundException e) {
333 Log.e(TAG, "Couldn't find resources for package", e);
334 }
335 return ri.loadIcon(mPm);
336 }
337
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800338 @Override
339 protected void onRestart() {
340 super.onRestart();
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700341 if (!mRegistered) {
342 mPackageMonitor.register(this, getMainLooper(), false);
343 mRegistered = true;
344 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800345 mAdapter.handlePackagesChanged();
346 }
347
348 @Override
349 protected void onStop() {
350 super.onStop();
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700351 if (mRegistered) {
352 mPackageMonitor.unregister();
353 mRegistered = false;
354 }
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700355 if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
356 // This resolver is in the unusual situation where it has been
357 // launched at the top of a new task. We don't let it be added
358 // to the recent tasks shown to the user, and we need to make sure
359 // that each time we are launched we get the correct launching
360 // uid (not re-using the same resolver from an old launching uid),
361 // so we will now finish ourself since being no longer visible,
362 // the user probably can't get back to us.
363 if (!isChangingConfigurations()) {
364 finish();
365 }
366 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800367 }
368
Adam Powellc5878612012-05-04 18:42:38 -0700369 @Override
Adam Powell9bee4662012-05-08 11:07:23 -0700370 protected void onRestoreInstanceState(Bundle savedInstanceState) {
371 super.onRestoreInstanceState(savedInstanceState);
372 if (mAlwaysUseOption) {
Adam Powelle9414d92014-07-05 17:44:18 -0700373 final int checkedPos = mGridView.getCheckedItemPosition();
Nicolas Prevot50449882014-06-23 12:42:37 +0100374 final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
Adam Powelld81cc4a2012-07-19 13:51:39 -0700375 mLastSelected = checkedPos;
Adam Powell278902c2014-07-12 18:33:22 -0700376 setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
Nicolas Prevot50449882014-06-23 12:42:37 +0100377 mOnceButton.setEnabled(hasValidSelection);
378 if (hasValidSelection) {
Adam Powelle9414d92014-07-05 17:44:18 -0700379 mGridView.setSelection(checkedPos);
Adam Powell9bee4662012-05-08 11:07:23 -0700380 }
381 }
382 }
383
384 @Override
Adam Powellc5878612012-05-04 18:42:38 -0700385 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Adam Powelle9414d92014-07-05 17:44:18 -0700386 final int checkedPos = mGridView.getCheckedItemPosition();
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700387 final boolean hasValidSelection = checkedPos != ListView.INVALID_POSITION;
Adam Powellbdda4e72012-07-20 11:22:03 -0700388 if (mAlwaysUseOption && (!hasValidSelection || mLastSelected != checkedPos)) {
Adam Powell278902c2014-07-12 18:33:22 -0700389 setAlwaysButtonEnabled(hasValidSelection, checkedPos, true);
Adam Powelld81cc4a2012-07-19 13:51:39 -0700390 mOnceButton.setEnabled(hasValidSelection);
391 if (hasValidSelection) {
Adam Powelle9414d92014-07-05 17:44:18 -0700392 mGridView.smoothScrollToPosition(checkedPos);
Adam Powell9bee4662012-05-08 11:07:23 -0700393 }
Adam Powelld81cc4a2012-07-19 13:51:39 -0700394 mLastSelected = checkedPos;
Adam Powellc5878612012-05-04 18:42:38 -0700395 } else {
Adam Powell278902c2014-07-12 18:33:22 -0700396 startSelected(position, false, true);
Adam Powellc5878612012-05-04 18:42:38 -0700397 }
398 }
399
Adam Powell278902c2014-07-12 18:33:22 -0700400 private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos,
401 boolean filtered) {
Nicolas Prevot50449882014-06-23 12:42:37 +0100402 boolean enabled = false;
403 if (hasValidSelection) {
Adam Powell278902c2014-07-12 18:33:22 -0700404 ResolveInfo ri = mAdapter.resolveInfoForPosition(checkedPos, filtered);
Nicolas Prevot50449882014-06-23 12:42:37 +0100405 if (ri.targetUserId == UserHandle.USER_CURRENT) {
406 enabled = true;
407 }
408 }
409 mAlwaysButton.setEnabled(enabled);
410 }
411
Adam Powellc5878612012-05-04 18:42:38 -0700412 public void onButtonClick(View v) {
413 final int id = v.getId();
Adam Powell278902c2014-07-12 18:33:22 -0700414 startSelected(mAlwaysUseOption ?
415 mGridView.getCheckedItemPosition() : mAdapter.getFilteredPosition(),
416 id == R.id.button_always,
417 mAlwaysUseOption);
Adam Powellc5878612012-05-04 18:42:38 -0700418 dismiss();
419 }
420
Adam Powell278902c2014-07-12 18:33:22 -0700421 void startSelected(int which, boolean always, boolean filtered) {
Amith Yamasani07cd3512013-09-18 13:16:00 -0700422 if (isFinishing()) {
423 return;
424 }
Adam Powell278902c2014-07-12 18:33:22 -0700425 ResolveInfo ri = mAdapter.resolveInfoForPosition(which, filtered);
426 Intent intent = mAdapter.intentForPosition(which, filtered);
Adam Powellc5878612012-05-04 18:42:38 -0700427 onIntentSelected(ri, intent, always);
Mike Lockwood02eb8742011-02-27 09:10:37 -0800428 finish();
429 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430
Mike Lockwood02eb8742011-02-27 09:10:37 -0800431 protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
Adam Powell278902c2014-07-12 18:33:22 -0700432 if ((mAlwaysUseOption || mAdapter.hasFilteredItem()) && mAdapter.mOrigResolveList != null) {
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700433 // Build a reasonable intent filter, based on what matched.
434 IntentFilter filter = new IntentFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700436 if (intent.getAction() != null) {
437 filter.addAction(intent.getAction());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 }
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700439 Set<String> categories = intent.getCategories();
440 if (categories != null) {
441 for (String cat : categories) {
442 filter.addCategory(cat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 }
444 }
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700445 filter.addCategory(Intent.CATEGORY_DEFAULT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700447 int cat = ri.match&IntentFilter.MATCH_CATEGORY_MASK;
448 Uri data = intent.getData();
449 if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
450 String mimeType = intent.resolveType(this);
451 if (mimeType != null) {
452 try {
453 filter.addDataType(mimeType);
454 } catch (IntentFilter.MalformedMimeTypeException e) {
455 Log.w("ResolverActivity", e);
456 filter = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 }
458 }
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700459 }
460 if (data != null && data.getScheme() != null) {
461 // We need the data specification if there was no type,
462 // OR if the scheme is not one of our magical "file:"
463 // or "content:" schemes (see IntentFilter for the reason).
464 if (cat != IntentFilter.MATCH_CATEGORY_TYPE
465 || (!"file".equals(data.getScheme())
466 && !"content".equals(data.getScheme()))) {
467 filter.addDataScheme(data.getScheme());
468
469 // Look through the resolved filter to determine which part
470 // of it matched the original Intent.
471 Iterator<PatternMatcher> pIt = ri.filter.schemeSpecificPartsIterator();
472 if (pIt != null) {
473 String ssp = data.getSchemeSpecificPart();
474 while (ssp != null && pIt.hasNext()) {
475 PatternMatcher p = pIt.next();
476 if (p.match(ssp)) {
477 filter.addDataSchemeSpecificPart(p.getPath(), p.getType());
478 break;
479 }
Dianne Hackborndf1c0bf2013-06-12 16:21:38 -0700480 }
481 }
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700482 Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();
483 if (aIt != null) {
484 while (aIt.hasNext()) {
485 IntentFilter.AuthorityEntry a = aIt.next();
486 if (a.match(data) >= 0) {
487 int port = a.getPort();
488 filter.addDataAuthority(a.getHost(),
489 port >= 0 ? Integer.toString(port) : null);
490 break;
491 }
492 }
493 }
494 pIt = ri.filter.pathsIterator();
495 if (pIt != null) {
496 String path = data.getPath();
497 while (path != null && pIt.hasNext()) {
498 PatternMatcher p = pIt.next();
499 if (p.match(path)) {
500 filter.addDataPath(p.getPath(), p.getType());
501 break;
502 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 }
504 }
505 }
506 }
507
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700508 if (filter != null) {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700509 final int N = mAdapter.mOrigResolveList.size();
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700510 ComponentName[] set = new ComponentName[N];
511 int bestMatch = 0;
512 for (int i=0; i<N; i++) {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700513 ResolveInfo r = mAdapter.mOrigResolveList.get(i);
Amith Yamasani588dd2a2013-09-03 12:30:44 -0700514 set[i] = new ComponentName(r.activityInfo.packageName,
515 r.activityInfo.name);
516 if (r.match > bestMatch) bestMatch = r.match;
517 }
518 if (alwaysCheck) {
519 getPackageManager().addPreferredActivity(filter, bestMatch, set,
520 intent.getComponent());
521 } else {
522 try {
523 AppGlobals.getPackageManager().setLastChosenActivity(intent,
524 intent.resolveTypeIfNeeded(getContentResolver()),
525 PackageManager.MATCH_DEFAULT_ONLY,
526 filter, bestMatch, intent.getComponent());
527 } catch (RemoteException re) {
528 Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
529 }
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700530 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 }
532 }
533
534 if (intent != null) {
Amith Yamasani203a2f42012-10-03 20:16:40 -0700535 startActivity(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 }
538
Adam Powellc5878612012-05-04 18:42:38 -0700539 void showAppDetails(ResolveInfo ri) {
540 Intent in = new Intent().setAction("android.settings.APPLICATION_DETAILS_SETTINGS")
Adam Powell0fc5b2b2012-07-18 18:20:29 -0700541 .setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
542 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
Amith Yamasani203a2f42012-10-03 20:16:40 -0700543 startActivity(in);
Adam Powellc5878612012-05-04 18:42:38 -0700544 }
545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 private final class DisplayResolveInfo {
547 ResolveInfo ri;
548 CharSequence displayLabel;
Dianne Hackborneb034652009-09-07 00:49:58 -0700549 Drawable displayIcon;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800550 CharSequence extendedInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -0700551 Intent origIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552
Dianne Hackborneb034652009-09-07 00:49:58 -0700553 DisplayResolveInfo(ResolveInfo pri, CharSequence pLabel,
554 CharSequence pInfo, Intent pOrigIntent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800555 ri = pri;
556 displayLabel = pLabel;
557 extendedInfo = pInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -0700558 origIntent = pOrigIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 }
560 }
561
562 private final class ResolveListAdapter extends BaseAdapter {
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800563 private final Intent[] mInitialIntents;
564 private final List<ResolveInfo> mBaseResolveList;
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700565 private ResolveInfo mLastChosen;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800566 private final Intent mIntent;
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700567 private final int mLaunchedFromUid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800568 private final LayoutInflater mInflater;
569
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700570 List<DisplayResolveInfo> mList;
571 List<ResolveInfo> mOrigResolveList;
572
Adam Powell278902c2014-07-12 18:33:22 -0700573 private int mLastChosenPosition = -1;
574 private boolean mFilterLastUsed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575
Dianne Hackborneb034652009-09-07 00:49:58 -0700576 public ResolveListAdapter(Context context, Intent intent,
Adam Powell278902c2014-07-12 18:33:22 -0700577 Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid,
578 boolean filterLastUsed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 mIntent = new Intent(intent);
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800580 mInitialIntents = initialIntents;
581 mBaseResolveList = rList;
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700582 mLaunchedFromUid = launchedFromUid;
Adam Powelle9414d92014-07-05 17:44:18 -0700583 mInflater = LayoutInflater.from(context);
You Kim43a5070e2012-11-21 23:23:45 +0900584 mList = new ArrayList<DisplayResolveInfo>();
Adam Powell278902c2014-07-12 18:33:22 -0700585 mFilterLastUsed = filterLastUsed;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800586 rebuildList();
587 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800589 public void handlePackagesChanged() {
Adam Powellc5878612012-05-04 18:42:38 -0700590 final int oldItemCount = getCount();
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800591 rebuildList();
592 notifyDataSetChanged();
You Kim43a5070e2012-11-21 23:23:45 +0900593 final int newItemCount = getCount();
594 if (newItemCount == 0) {
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800595 // We no longer have any items... just finish the activity.
596 finish();
Adam Powelle9414d92014-07-05 17:44:18 -0700597 } else if (newItemCount != oldItemCount) {
598 resizeGrid();
Adam Powellc5878612012-05-04 18:42:38 -0700599 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800600 }
601
Adam Powell278902c2014-07-12 18:33:22 -0700602 public DisplayResolveInfo getFilteredItem() {
603 if (mFilterLastUsed && mLastChosenPosition >= 0) {
604 // Not using getItem since it offsets to dodge this position for the list
605 return mList.get(mLastChosenPosition);
606 }
607 return null;
608 }
609
610 public int getFilteredPosition() {
611 if (mFilterLastUsed && mLastChosenPosition >= 0) {
612 return mLastChosenPosition;
613 }
614 return AbsListView.INVALID_POSITION;
615 }
616
617 public boolean hasFilteredItem() {
618 return mFilterLastUsed && mLastChosenPosition >= 0;
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700619 }
620
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800621 private void rebuildList() {
You Kim43a5070e2012-11-21 23:23:45 +0900622 List<ResolveInfo> currentResolveList;
623
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700624 try {
625 mLastChosen = AppGlobals.getPackageManager().getLastChosenActivity(
626 mIntent, mIntent.resolveTypeIfNeeded(getContentResolver()),
627 PackageManager.MATCH_DEFAULT_ONLY);
628 } catch (RemoteException re) {
629 Log.d(TAG, "Error calling setLastChosenActivity\n" + re);
630 }
631
You Kim43a5070e2012-11-21 23:23:45 +0900632 mList.clear();
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800633 if (mBaseResolveList != null) {
Xiong Lie88b0422014-04-10 15:25:45 +0800634 currentResolveList = mOrigResolveList = mBaseResolveList;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800635 } else {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700636 currentResolveList = mOrigResolveList = mPm.queryIntentActivities(
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800637 mIntent, PackageManager.MATCH_DEFAULT_ONLY
Adam Powell278902c2014-07-12 18:33:22 -0700638 | (mFilterLastUsed ? PackageManager.GET_RESOLVED_FILTER : 0));
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700639 // Filter out any activities that the launched uid does not
640 // have permission for. We don't do this when we have an explicit
641 // list of resolved activities, because that only happens when
642 // we are being subclassed, so we can safely launch whatever
643 // they gave us.
You Kim43a5070e2012-11-21 23:23:45 +0900644 if (currentResolveList != null) {
645 for (int i=currentResolveList.size()-1; i >= 0; i--) {
646 ActivityInfo ai = currentResolveList.get(i).activityInfo;
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700647 int granted = ActivityManager.checkComponentPermission(
648 ai.permission, mLaunchedFromUid,
649 ai.applicationInfo.uid, ai.exported);
650 if (granted != PackageManager.PERMISSION_GRANTED) {
651 // Access not allowed!
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700652 if (mOrigResolveList == currentResolveList) {
653 mOrigResolveList = new ArrayList<ResolveInfo>(mOrigResolveList);
654 }
You Kim43a5070e2012-11-21 23:23:45 +0900655 currentResolveList.remove(i);
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700656 }
657 }
658 }
Jeff Hamiltond88e9aa2011-01-24 14:53:00 -0600659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660 int N;
You Kim43a5070e2012-11-21 23:23:45 +0900661 if ((currentResolveList != null) && ((N = currentResolveList.size()) > 0)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 // Only display the first matches that are either of equal
663 // priority or have asked to be default options.
You Kim43a5070e2012-11-21 23:23:45 +0900664 ResolveInfo r0 = currentResolveList.get(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800665 for (int i=1; i<N; i++) {
You Kim43a5070e2012-11-21 23:23:45 +0900666 ResolveInfo ri = currentResolveList.get(i);
667 if (DEBUG) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 "ResolveListActivity",
669 r0.activityInfo.name + "=" +
670 r0.priority + "/" + r0.isDefault + " vs " +
671 ri.activityInfo.name + "=" +
672 ri.priority + "/" + ri.isDefault);
You Kim43a5070e2012-11-21 23:23:45 +0900673 if (r0.priority != ri.priority ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 r0.isDefault != ri.isDefault) {
675 while (i < N) {
Dianne Hackborn6d8dfbd2013-09-23 17:38:51 -0700676 if (mOrigResolveList == currentResolveList) {
677 mOrigResolveList = new ArrayList<ResolveInfo>(mOrigResolveList);
678 }
You Kim43a5070e2012-11-21 23:23:45 +0900679 currentResolveList.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 N--;
681 }
682 }
683 }
684 if (N > 1) {
685 ResolveInfo.DisplayNameComparator rComparator =
686 new ResolveInfo.DisplayNameComparator(mPm);
You Kim43a5070e2012-11-21 23:23:45 +0900687 Collections.sort(currentResolveList, rComparator);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 }
Dianne Hackborneb034652009-09-07 00:49:58 -0700689 // First put the initial items at the top.
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800690 if (mInitialIntents != null) {
691 for (int i=0; i<mInitialIntents.length; i++) {
692 Intent ii = mInitialIntents[i];
Dianne Hackborneb034652009-09-07 00:49:58 -0700693 if (ii == null) {
694 continue;
695 }
696 ActivityInfo ai = ii.resolveActivityInfo(
697 getPackageManager(), 0);
698 if (ai == null) {
699 Log.w("ResolverActivity", "No activity found for "
700 + ii);
701 continue;
702 }
703 ResolveInfo ri = new ResolveInfo();
704 ri.activityInfo = ai;
705 if (ii instanceof LabeledIntent) {
706 LabeledIntent li = (LabeledIntent)ii;
707 ri.resolvePackageName = li.getSourcePackage();
708 ri.labelRes = li.getLabelResource();
709 ri.nonLocalizedLabel = li.getNonLocalizedLabel();
710 ri.icon = li.getIconResource();
711 }
712 mList.add(new DisplayResolveInfo(ri,
713 ri.loadLabel(getPackageManager()), null, ii));
714 }
715 }
You Kim43a5070e2012-11-21 23:23:45 +0900716
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717 // Check for applications with same name and use application name or
718 // package name if necessary
You Kim43a5070e2012-11-21 23:23:45 +0900719 r0 = currentResolveList.get(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800720 int start = 0;
721 CharSequence r0Label = r0.loadLabel(mPm);
Adam Powellc5878612012-05-04 18:42:38 -0700722 mShowExtended = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 for (int i = 1; i < N; i++) {
724 if (r0Label == null) {
725 r0Label = r0.activityInfo.packageName;
726 }
You Kim43a5070e2012-11-21 23:23:45 +0900727 ResolveInfo ri = currentResolveList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 CharSequence riLabel = ri.loadLabel(mPm);
729 if (riLabel == null) {
730 riLabel = ri.activityInfo.packageName;
731 }
732 if (riLabel.equals(r0Label)) {
733 continue;
734 }
You Kim43a5070e2012-11-21 23:23:45 +0900735 processGroup(currentResolveList, start, (i-1), r0, r0Label);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800736 r0 = ri;
737 r0Label = riLabel;
738 start = i;
739 }
740 // Process last group
You Kim43a5070e2012-11-21 23:23:45 +0900741 processGroup(currentResolveList, start, (N-1), r0, r0Label);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 }
743 }
744
745 private void processGroup(List<ResolveInfo> rList, int start, int end, ResolveInfo ro,
746 CharSequence roLabel) {
747 // Process labels from start to i
748 int num = end - start+1;
749 if (num == 1) {
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700750 if (mLastChosen != null
751 && mLastChosen.activityInfo.packageName.equals(
752 ro.activityInfo.packageName)
753 && mLastChosen.activityInfo.name.equals(ro.activityInfo.name)) {
Adam Powell278902c2014-07-12 18:33:22 -0700754 mLastChosenPosition = mList.size();
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700755 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800756 // No duplicate labels. Use label for entry at start
Dianne Hackborneb034652009-09-07 00:49:58 -0700757 mList.add(new DisplayResolveInfo(ro, roLabel, null, null));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 } else {
Adam Powellc5878612012-05-04 18:42:38 -0700759 mShowExtended = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 boolean usePkg = false;
761 CharSequence startApp = ro.activityInfo.applicationInfo.loadLabel(mPm);
762 if (startApp == null) {
763 usePkg = true;
764 }
765 if (!usePkg) {
766 // Use HashSet to track duplicates
767 HashSet<CharSequence> duplicates =
768 new HashSet<CharSequence>();
769 duplicates.add(startApp);
770 for (int j = start+1; j <= end ; j++) {
771 ResolveInfo jRi = rList.get(j);
772 CharSequence jApp = jRi.activityInfo.applicationInfo.loadLabel(mPm);
773 if ( (jApp == null) || (duplicates.contains(jApp))) {
774 usePkg = true;
775 break;
776 } else {
777 duplicates.add(jApp);
778 }
779 }
780 // Clear HashSet for later use
781 duplicates.clear();
782 }
783 for (int k = start; k <= end; k++) {
784 ResolveInfo add = rList.get(k);
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700785 if (mLastChosen != null
786 && mLastChosen.activityInfo.packageName.equals(
787 add.activityInfo.packageName)
788 && mLastChosen.activityInfo.name.equals(add.activityInfo.name)) {
Adam Powell278902c2014-07-12 18:33:22 -0700789 mLastChosenPosition = mList.size();
Amith Yamasanie9ecc8b2013-08-22 11:16:27 -0700790 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800791 if (usePkg) {
792 // Use application name for all entries from start to end-1
793 mList.add(new DisplayResolveInfo(add, roLabel,
Dianne Hackborneb034652009-09-07 00:49:58 -0700794 add.activityInfo.packageName, null));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 } else {
796 // Use package name for all entries from start to end-1
797 mList.add(new DisplayResolveInfo(add, roLabel,
Dianne Hackborneb034652009-09-07 00:49:58 -0700798 add.activityInfo.applicationInfo.loadLabel(mPm), null));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 }
800 }
801 }
802 }
803
Adam Powell278902c2014-07-12 18:33:22 -0700804 public ResolveInfo resolveInfoForPosition(int position, boolean filtered) {
805 return (filtered ? getItem(position) : mList.get(position)).ri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 }
807
Adam Powell278902c2014-07-12 18:33:22 -0700808 public Intent intentForPosition(int position, boolean filtered) {
809 DisplayResolveInfo dri = filtered ? getItem(position) : mList.get(position);
Dianne Hackborneb034652009-09-07 00:49:58 -0700810
811 Intent intent = new Intent(dri.origIntent != null
812 ? dri.origIntent : mIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800813 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
814 |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
Dianne Hackborneb034652009-09-07 00:49:58 -0700815 ActivityInfo ai = dri.ri.activityInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 intent.setComponent(new ComponentName(
817 ai.applicationInfo.packageName, ai.name));
818 return intent;
819 }
820
821 public int getCount() {
Adam Powell278902c2014-07-12 18:33:22 -0700822 int result = mList.size();
823 if (mFilterLastUsed && mLastChosenPosition >= 0) {
824 result--;
825 }
826 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 }
828
Adam Powell278902c2014-07-12 18:33:22 -0700829 public DisplayResolveInfo getItem(int position) {
830 if (mFilterLastUsed && mLastChosenPosition >= 0 && position >= mLastChosenPosition) {
831 position++;
832 }
You Kim43a5070e2012-11-21 23:23:45 +0900833 return mList.get(position);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 }
835
836 public long getItemId(int position) {
837 return position;
838 }
839
840 public View getView(int position, View convertView, ViewGroup parent) {
841 View view;
842 if (convertView == null) {
843 view = mInflater.inflate(
844 com.android.internal.R.layout.resolve_list_item, parent, false);
Adam Powellc5878612012-05-04 18:42:38 -0700845
Adam Powell0256c6f2013-05-29 16:42:33 -0700846 final ViewHolder holder = new ViewHolder(view);
847 view.setTag(holder);
848
Adam Powellc5878612012-05-04 18:42:38 -0700849 // Fix the icon size even if we have different sized resources
Adam Powell0256c6f2013-05-29 16:42:33 -0700850 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
Adam Powellc5878612012-05-04 18:42:38 -0700851 lp.width = lp.height = mIconSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800852 } else {
853 view = convertView;
854 }
Adam Powell278902c2014-07-12 18:33:22 -0700855 bindView(view, getItem(position));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800856 return view;
857 }
858
859 private final void bindView(View view, DisplayResolveInfo info) {
Adam Powell0256c6f2013-05-29 16:42:33 -0700860 final ViewHolder holder = (ViewHolder) view.getTag();
861 holder.text.setText(info.displayLabel);
Adam Powellc5878612012-05-04 18:42:38 -0700862 if (mShowExtended) {
Adam Powell0256c6f2013-05-29 16:42:33 -0700863 holder.text2.setVisibility(View.VISIBLE);
864 holder.text2.setText(info.extendedInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800865 } else {
Adam Powell0256c6f2013-05-29 16:42:33 -0700866 holder.text2.setVisibility(View.GONE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867 }
Dianne Hackborneb034652009-09-07 00:49:58 -0700868 if (info.displayIcon == null) {
Adam Powell0256c6f2013-05-29 16:42:33 -0700869 new LoadIconTask().execute(info);
Dianne Hackborneb034652009-09-07 00:49:58 -0700870 }
Adam Powell0256c6f2013-05-29 16:42:33 -0700871 holder.icon.setImageDrawable(info.displayIcon);
872 }
873 }
874
875 static class ViewHolder {
876 public TextView text;
877 public TextView text2;
878 public ImageView icon;
879
880 public ViewHolder(View view) {
881 text = (TextView) view.findViewById(com.android.internal.R.id.text1);
882 text2 = (TextView) view.findViewById(com.android.internal.R.id.text2);
883 icon = (ImageView) view.findViewById(R.id.icon);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800884 }
885 }
886
Adam Powell2d809622012-03-22 15:24:43 -0700887 class ItemLongClickListener implements AdapterView.OnItemLongClickListener {
888
889 @Override
890 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
Adam Powell278902c2014-07-12 18:33:22 -0700891 ResolveInfo ri = mAdapter.resolveInfoForPosition(position, true);
Adam Powellc5878612012-05-04 18:42:38 -0700892 showAppDetails(ri);
Adam Powell2d809622012-03-22 15:24:43 -0700893 return true;
894 }
895
896 }
Adam Powell0256c6f2013-05-29 16:42:33 -0700897
898 class LoadIconTask extends AsyncTask<DisplayResolveInfo, Void, DisplayResolveInfo> {
899 @Override
900 protected DisplayResolveInfo doInBackground(DisplayResolveInfo... params) {
901 final DisplayResolveInfo info = params[0];
902 if (info.displayIcon == null) {
903 info.displayIcon = loadIconForResolveInfo(info.ri);
904 }
905 return info;
906 }
907
908 @Override
909 protected void onPostExecute(DisplayResolveInfo info) {
910 mAdapter.notifyDataSetChanged();
911 }
912 }
Adam Powell278902c2014-07-12 18:33:22 -0700913
914 class LoadIconIntoViewTask extends AsyncTask<DisplayResolveInfo, Void, DisplayResolveInfo> {
915 final ImageView mTargetView;
916
917 public LoadIconIntoViewTask(ImageView target) {
918 mTargetView = target;
919 }
920
921 @Override
922 protected DisplayResolveInfo doInBackground(DisplayResolveInfo... params) {
923 final DisplayResolveInfo info = params[0];
924 if (info.displayIcon == null) {
925 info.displayIcon = loadIconForResolveInfo(info.ri);
926 }
927 return info;
928 }
929
930 @Override
931 protected void onPostExecute(DisplayResolveInfo info) {
932 mTargetView.setImageDrawable(info.displayIcon);
933 }
934 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800935}
936