blob: 7334ac304af14176f7c6060db44020d96f05b9a3 [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
19import com.android.internal.R;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -080020import com.android.internal.content.PackageMonitor;
21
Adam Powellc5878612012-05-04 18:42:38 -070022import android.app.ActivityManager;
Dianne Hackborn5320eb82012-05-18 12:05:04 -070023import android.app.ActivityManagerNative;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import android.content.ComponentName;
25import android.content.Context;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.pm.ActivityInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -070029import android.content.pm.LabeledIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.content.pm.PackageManager;
Adam Powellc5878612012-05-04 18:42:38 -070031import android.content.pm.PackageManager.NameNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.content.pm.ResolveInfo;
Adam Powellc5878612012-05-04 18:42:38 -070033import android.content.res.Resources;
Dianne Hackborneb034652009-09-07 00:49:58 -070034import android.graphics.drawable.Drawable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.net.Uri;
36import android.os.Bundle;
37import android.os.PatternMatcher;
Dianne Hackborn5320eb82012-05-18 12:05:04 -070038import android.os.Process;
39import android.os.RemoteException;
40import android.os.UserId;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.util.Log;
Adam Powell2d809622012-03-22 15:24:43 -070042import android.view.LayoutInflater;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.view.View;
44import android.view.ViewGroup;
Adam Powell2d809622012-03-22 15:24:43 -070045import android.widget.AdapterView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.widget.BaseAdapter;
Adam Powellc5878612012-05-04 18:42:38 -070047import android.widget.Button;
48import android.widget.GridView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.widget.ImageView;
Adam Powell2d809622012-03-22 15:24:43 -070050import android.widget.ListView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.widget.TextView;
Adam Powell2d809622012-03-22 15:24:43 -070052
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import java.util.ArrayList;
54import java.util.Collections;
55import java.util.HashSet;
56import java.util.Iterator;
57import java.util.List;
58import java.util.Set;
59
60/**
61 * This activity is displayed when the system attempts to start an Intent for
62 * which there is more than one matching activity, allowing the user to decide
63 * which to go to. It is not normally used directly by application developers.
64 */
Adam Powellc5878612012-05-04 18:42:38 -070065public class ResolverActivity extends AlertActivity implements AdapterView.OnItemClickListener {
66 private static final String TAG = "ResolverActivity";
67
Dianne Hackborn5320eb82012-05-18 12:05:04 -070068 private int mLaunchedFromUid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069 private ResolveListAdapter mAdapter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070 private PackageManager mPm;
Adam Powellc5878612012-05-04 18:42:38 -070071 private boolean mAlwaysUseOption;
72 private boolean mShowExtended;
73 private GridView mGrid;
74 private Button mAlwaysButton;
75 private Button mOnceButton;
76 private int mIconDpi;
77 private int mIconSize;
Adam Powell589e6f92012-05-06 20:52:38 -070078 private int mMaxColumns;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
Dianne Hackbornd44713a2012-04-30 16:34:46 -070080 private boolean mRegistered;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -080081 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
82 @Override public void onSomePackagesChanged() {
83 mAdapter.handlePackagesChanged();
84 }
85 };
86
Dianne Hackborn905577f2011-09-07 18:31:28 -070087 private Intent makeMyIntent() {
88 Intent intent = new Intent(getIntent());
89 // The resolver activity is set to be hidden from recent tasks.
90 // we don't want this attribute to be propagated to the next activity
91 // being launched. Note that if the original Intent also had this
92 // flag set, we are now losing it. That should be a very rare case
93 // and we can live with this.
94 intent.setFlags(intent.getFlags()&~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
95 return intent;
96 }
97
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 @Override
99 protected void onCreate(Bundle savedInstanceState) {
Dianne Hackborn905577f2011-09-07 18:31:28 -0700100 onCreate(savedInstanceState, makeMyIntent(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 getResources().getText(com.android.internal.R.string.whichApplication),
Jeff Hamiltond88e9aa2011-01-24 14:53:00 -0600102 null, null, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 }
104
105 protected void onCreate(Bundle savedInstanceState, Intent intent,
Jeff Hamiltond88e9aa2011-01-24 14:53:00 -0600106 CharSequence title, Intent[] initialIntents, List<ResolveInfo> rList,
Mike Lockwoodbce6f8f2011-03-13 17:26:52 -0400107 boolean alwaysUseOption) {
Adam Powellc5878612012-05-04 18:42:38 -0700108 setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 super.onCreate(savedInstanceState);
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700110 try {
111 mLaunchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
112 getActivityToken());
113 } catch (RemoteException e) {
114 mLaunchedFromUid = -1;
115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 mPm = getPackageManager();
Adam Powellc5878612012-05-04 18:42:38 -0700117 mAlwaysUseOption = alwaysUseOption;
Adam Powell589e6f92012-05-06 20:52:38 -0700118 mMaxColumns = getResources().getInteger(R.integer.config_maxResolverActivityColumns);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 intent.setComponent(null);
120
121 AlertController.AlertParams ap = mAlertParams;
122
123 ap.mTitle = title;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700125 mPackageMonitor.register(this, getMainLooper(), false);
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700126 mRegistered = true;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800127
Adam Powellc5878612012-05-04 18:42:38 -0700128 final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
129 mIconDpi = am.getLauncherLargeIconDensity();
130 mIconSize = am.getLauncherLargeIconSize();
131
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700132 mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList,
133 mLaunchedFromUid);
Mike Lockwood02eb8742011-02-27 09:10:37 -0800134 int count = mAdapter.getCount();
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700135 if (mLaunchedFromUid < 0 || UserId.isIsolated(mLaunchedFromUid)) {
136 // Gulp!
137 finish();
138 return;
139 } else if (count > 1) {
Adam Powellc5878612012-05-04 18:42:38 -0700140 ap.mView = getLayoutInflater().inflate(R.layout.resolver_grid, null);
141 mGrid = (GridView) ap.mView.findViewById(R.id.resolver_grid);
142 mGrid.setAdapter(mAdapter);
143 mGrid.setOnItemClickListener(this);
144 mGrid.setOnItemLongClickListener(new ItemLongClickListener());
145
146 if (alwaysUseOption) {
147 mGrid.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
148 }
149
150 resizeGrid();
Mike Lockwood02eb8742011-02-27 09:10:37 -0800151 } else if (count == 1) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 startActivity(mAdapter.intentForPosition(0));
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700153 mPackageMonitor.unregister();
154 mRegistered = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 finish();
156 return;
157 } else {
Adam Powellc5878612012-05-04 18:42:38 -0700158 ap.mMessage = getResources().getText(R.string.noApplications);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 }
160
161 setupAlert();
Adam Powell2d809622012-03-22 15:24:43 -0700162
Adam Powellc5878612012-05-04 18:42:38 -0700163 if (alwaysUseOption) {
164 final ViewGroup buttonLayout = (ViewGroup) findViewById(R.id.button_bar);
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700165 if (buttonLayout != null) {
166 buttonLayout.setVisibility(View.VISIBLE);
167 mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
168 mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
169 } else {
170 mAlwaysUseOption = false;
171 }
Adam Powell2d809622012-03-22 15:24:43 -0700172 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 }
174
Adam Powellc5878612012-05-04 18:42:38 -0700175 void resizeGrid() {
176 final int itemCount = mAdapter.getCount();
Adam Powell589e6f92012-05-06 20:52:38 -0700177 mGrid.setNumColumns(Math.min(itemCount, mMaxColumns));
Adam Powellc5878612012-05-04 18:42:38 -0700178 }
179
180 Drawable getIcon(Resources res, int resId) {
181 Drawable result;
182 try {
183 result = res.getDrawableForDensity(resId, mIconDpi);
184 } catch (Resources.NotFoundException e) {
185 result = null;
186 }
187
188 return result;
189 }
190
191 Drawable loadIconForResolveInfo(ResolveInfo ri) {
192 Drawable dr;
193 try {
194 if (ri.resolvePackageName != null && ri.icon != 0) {
195 dr = getIcon(mPm.getResourcesForApplication(ri.resolvePackageName), ri.icon);
196 if (dr != null) {
197 return dr;
198 }
199 }
200 final int iconRes = ri.getIconResource();
201 if (iconRes != 0) {
202 dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.packageName), iconRes);
203 if (dr != null) {
204 return dr;
205 }
206 }
207 } catch (NameNotFoundException e) {
208 Log.e(TAG, "Couldn't find resources for package", e);
209 }
210 return ri.loadIcon(mPm);
211 }
212
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800213 @Override
214 protected void onRestart() {
215 super.onRestart();
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700216 if (!mRegistered) {
217 mPackageMonitor.register(this, getMainLooper(), false);
218 mRegistered = true;
219 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800220 mAdapter.handlePackagesChanged();
221 }
222
223 @Override
224 protected void onStop() {
225 super.onStop();
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700226 if (mRegistered) {
227 mPackageMonitor.unregister();
228 mRegistered = false;
229 }
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700230 if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
231 // This resolver is in the unusual situation where it has been
232 // launched at the top of a new task. We don't let it be added
233 // to the recent tasks shown to the user, and we need to make sure
234 // that each time we are launched we get the correct launching
235 // uid (not re-using the same resolver from an old launching uid),
236 // so we will now finish ourself since being no longer visible,
237 // the user probably can't get back to us.
238 if (!isChangingConfigurations()) {
239 finish();
240 }
241 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800242 }
243
Adam Powellc5878612012-05-04 18:42:38 -0700244 @Override
Adam Powell9bee4662012-05-08 11:07:23 -0700245 protected void onRestoreInstanceState(Bundle savedInstanceState) {
246 super.onRestoreInstanceState(savedInstanceState);
247 if (mAlwaysUseOption) {
248 final int checkedPos = mGrid.getCheckedItemPosition();
249 final boolean enabled = checkedPos != GridView.INVALID_POSITION;
250 mAlwaysButton.setEnabled(enabled);
251 mOnceButton.setEnabled(enabled);
252 if (enabled) {
253 mGrid.setSelection(checkedPos);
254 }
255 }
256 }
257
258 @Override
Adam Powellc5878612012-05-04 18:42:38 -0700259 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
260 if (mAlwaysUseOption) {
261 final int checkedPos = mGrid.getCheckedItemPosition();
262 final boolean enabled = checkedPos != GridView.INVALID_POSITION;
263 mAlwaysButton.setEnabled(enabled);
264 mOnceButton.setEnabled(enabled);
Adam Powell9bee4662012-05-08 11:07:23 -0700265 if (enabled) {
266 mGrid.smoothScrollToPosition(checkedPos);
267 }
Adam Powellc5878612012-05-04 18:42:38 -0700268 } else {
269 startSelected(position, false);
270 }
271 }
272
273 public void onButtonClick(View v) {
274 final int id = v.getId();
275 startSelected(mGrid.getCheckedItemPosition(), id == R.id.button_always);
276 dismiss();
277 }
278
279 void startSelected(int which, boolean always) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280 ResolveInfo ri = mAdapter.resolveInfoForPosition(which);
281 Intent intent = mAdapter.intentForPosition(which);
Adam Powellc5878612012-05-04 18:42:38 -0700282 onIntentSelected(ri, intent, always);
Mike Lockwood02eb8742011-02-27 09:10:37 -0800283 finish();
284 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285
Mike Lockwood02eb8742011-02-27 09:10:37 -0800286 protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
287 if (alwaysCheck) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288 // Build a reasonable intent filter, based on what matched.
289 IntentFilter filter = new IntentFilter();
290
291 if (intent.getAction() != null) {
292 filter.addAction(intent.getAction());
293 }
294 Set<String> categories = intent.getCategories();
295 if (categories != null) {
296 for (String cat : categories) {
297 filter.addCategory(cat);
298 }
299 }
300 filter.addCategory(Intent.CATEGORY_DEFAULT);
301
302 int cat = ri.match&IntentFilter.MATCH_CATEGORY_MASK;
303 Uri data = intent.getData();
304 if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
305 String mimeType = intent.resolveType(this);
306 if (mimeType != null) {
307 try {
308 filter.addDataType(mimeType);
309 } catch (IntentFilter.MalformedMimeTypeException e) {
310 Log.w("ResolverActivity", e);
311 filter = null;
312 }
313 }
Dianne Hackborn5ef402b2010-03-26 17:17:25 -0700314 }
315 if (data != null && data.getScheme() != null) {
316 // We need the data specification if there was no type,
317 // OR if the scheme is not one of our magical "file:"
318 // or "content:" schemes (see IntentFilter for the reason).
319 if (cat != IntentFilter.MATCH_CATEGORY_TYPE
320 || (!"file".equals(data.getScheme())
321 && !"content".equals(data.getScheme()))) {
322 filter.addDataScheme(data.getScheme());
323
324 // Look through the resolved filter to determine which part
325 // of it matched the original Intent.
326 Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();
327 if (aIt != null) {
328 while (aIt.hasNext()) {
329 IntentFilter.AuthorityEntry a = aIt.next();
330 if (a.match(data) >= 0) {
331 int port = a.getPort();
332 filter.addDataAuthority(a.getHost(),
333 port >= 0 ? Integer.toString(port) : null);
334 break;
335 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 }
337 }
Dianne Hackborn5ef402b2010-03-26 17:17:25 -0700338 Iterator<PatternMatcher> pIt = ri.filter.pathsIterator();
339 if (pIt != null) {
340 String path = data.getPath();
341 while (path != null && pIt.hasNext()) {
342 PatternMatcher p = pIt.next();
343 if (p.match(path)) {
344 filter.addDataPath(p.getPath(), p.getType());
345 break;
346 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800347 }
348 }
349 }
350 }
351
352 if (filter != null) {
353 final int N = mAdapter.mList.size();
354 ComponentName[] set = new ComponentName[N];
355 int bestMatch = 0;
356 for (int i=0; i<N; i++) {
357 ResolveInfo r = mAdapter.mList.get(i).ri;
358 set[i] = new ComponentName(r.activityInfo.packageName,
359 r.activityInfo.name);
360 if (r.match > bestMatch) bestMatch = r.match;
361 }
362 getPackageManager().addPreferredActivity(filter, bestMatch, set,
363 intent.getComponent());
364 }
365 }
366
367 if (intent != null) {
368 startActivity(intent);
369 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 }
371
Adam Powellc5878612012-05-04 18:42:38 -0700372 void showAppDetails(ResolveInfo ri) {
373 Intent in = new Intent().setAction("android.settings.APPLICATION_DETAILS_SETTINGS")
374 .setData(Uri.fromParts("package", ri.activityInfo.packageName, null));
375 startActivity(in);
376 }
377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 private final class DisplayResolveInfo {
379 ResolveInfo ri;
380 CharSequence displayLabel;
Dianne Hackborneb034652009-09-07 00:49:58 -0700381 Drawable displayIcon;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 CharSequence extendedInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -0700383 Intent origIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384
Dianne Hackborneb034652009-09-07 00:49:58 -0700385 DisplayResolveInfo(ResolveInfo pri, CharSequence pLabel,
386 CharSequence pInfo, Intent pOrigIntent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 ri = pri;
388 displayLabel = pLabel;
389 extendedInfo = pInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -0700390 origIntent = pOrigIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 }
392 }
393
394 private final class ResolveListAdapter extends BaseAdapter {
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800395 private final Intent[] mInitialIntents;
396 private final List<ResolveInfo> mBaseResolveList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397 private final Intent mIntent;
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700398 private final int mLaunchedFromUid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 private final LayoutInflater mInflater;
400
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800401 private List<ResolveInfo> mCurrentResolveList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800402 private List<DisplayResolveInfo> mList;
403
Dianne Hackborneb034652009-09-07 00:49:58 -0700404 public ResolveListAdapter(Context context, Intent intent,
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700405 Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 mIntent = new Intent(intent);
407 mIntent.setComponent(null);
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800408 mInitialIntents = initialIntents;
409 mBaseResolveList = rList;
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700410 mLaunchedFromUid = launchedFromUid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800412 rebuildList();
413 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800415 public void handlePackagesChanged() {
Adam Powellc5878612012-05-04 18:42:38 -0700416 final int oldItemCount = getCount();
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800417 rebuildList();
418 notifyDataSetChanged();
419 if (mList.size() <= 0) {
420 // We no longer have any items... just finish the activity.
421 finish();
422 }
Adam Powellc5878612012-05-04 18:42:38 -0700423
424 final int newItemCount = getCount();
425 if (newItemCount != oldItemCount) {
426 resizeGrid();
427 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800428 }
429
430 private void rebuildList() {
431 if (mBaseResolveList != null) {
432 mCurrentResolveList = mBaseResolveList;
433 } else {
434 mCurrentResolveList = mPm.queryIntentActivities(
435 mIntent, PackageManager.MATCH_DEFAULT_ONLY
Adam Powellc5878612012-05-04 18:42:38 -0700436 | (mAlwaysUseOption ? PackageManager.GET_RESOLVED_FILTER : 0));
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700437 // Filter out any activities that the launched uid does not
438 // have permission for. We don't do this when we have an explicit
439 // list of resolved activities, because that only happens when
440 // we are being subclassed, so we can safely launch whatever
441 // they gave us.
442 if (mCurrentResolveList != null) {
443 for (int i=mCurrentResolveList.size()-1; i >= 0; i--) {
444 ActivityInfo ai = mCurrentResolveList.get(i).activityInfo;
445 int granted = ActivityManager.checkComponentPermission(
446 ai.permission, mLaunchedFromUid,
447 ai.applicationInfo.uid, ai.exported);
448 if (granted != PackageManager.PERMISSION_GRANTED) {
449 // Access not allowed!
450 mCurrentResolveList.remove(i);
451 }
452 }
453 }
Jeff Hamiltond88e9aa2011-01-24 14:53:00 -0600454 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 int N;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800456 if ((mCurrentResolveList != null) && ((N = mCurrentResolveList.size()) > 0)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800457 // Only display the first matches that are either of equal
458 // priority or have asked to be default options.
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800459 ResolveInfo r0 = mCurrentResolveList.get(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 for (int i=1; i<N; i++) {
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800461 ResolveInfo ri = mCurrentResolveList.get(i);
Joe Onorato43a17652011-04-06 19:22:23 -0700462 if (false) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 "ResolveListActivity",
464 r0.activityInfo.name + "=" +
465 r0.priority + "/" + r0.isDefault + " vs " +
466 ri.activityInfo.name + "=" +
467 ri.priority + "/" + ri.isDefault);
468 if (r0.priority != ri.priority ||
469 r0.isDefault != ri.isDefault) {
470 while (i < N) {
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800471 mCurrentResolveList.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472 N--;
473 }
474 }
475 }
476 if (N > 1) {
477 ResolveInfo.DisplayNameComparator rComparator =
478 new ResolveInfo.DisplayNameComparator(mPm);
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800479 Collections.sort(mCurrentResolveList, rComparator);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 }
Dianne Hackborneb034652009-09-07 00:49:58 -0700481
482 mList = new ArrayList<DisplayResolveInfo>();
483
484 // First put the initial items at the top.
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800485 if (mInitialIntents != null) {
486 for (int i=0; i<mInitialIntents.length; i++) {
487 Intent ii = mInitialIntents[i];
Dianne Hackborneb034652009-09-07 00:49:58 -0700488 if (ii == null) {
489 continue;
490 }
491 ActivityInfo ai = ii.resolveActivityInfo(
492 getPackageManager(), 0);
493 if (ai == null) {
494 Log.w("ResolverActivity", "No activity found for "
495 + ii);
496 continue;
497 }
498 ResolveInfo ri = new ResolveInfo();
499 ri.activityInfo = ai;
500 if (ii instanceof LabeledIntent) {
501 LabeledIntent li = (LabeledIntent)ii;
502 ri.resolvePackageName = li.getSourcePackage();
503 ri.labelRes = li.getLabelResource();
504 ri.nonLocalizedLabel = li.getNonLocalizedLabel();
505 ri.icon = li.getIconResource();
506 }
507 mList.add(new DisplayResolveInfo(ri,
508 ri.loadLabel(getPackageManager()), null, ii));
509 }
510 }
511
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800512 // Check for applications with same name and use application name or
513 // package name if necessary
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800514 r0 = mCurrentResolveList.get(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 int start = 0;
516 CharSequence r0Label = r0.loadLabel(mPm);
Adam Powellc5878612012-05-04 18:42:38 -0700517 mShowExtended = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 for (int i = 1; i < N; i++) {
519 if (r0Label == null) {
520 r0Label = r0.activityInfo.packageName;
521 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800522 ResolveInfo ri = mCurrentResolveList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 CharSequence riLabel = ri.loadLabel(mPm);
524 if (riLabel == null) {
525 riLabel = ri.activityInfo.packageName;
526 }
527 if (riLabel.equals(r0Label)) {
528 continue;
529 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800530 processGroup(mCurrentResolveList, start, (i-1), r0, r0Label);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 r0 = ri;
532 r0Label = riLabel;
533 start = i;
534 }
535 // Process last group
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800536 processGroup(mCurrentResolveList, start, (N-1), r0, r0Label);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800537 }
538 }
539
540 private void processGroup(List<ResolveInfo> rList, int start, int end, ResolveInfo ro,
541 CharSequence roLabel) {
542 // Process labels from start to i
543 int num = end - start+1;
544 if (num == 1) {
545 // No duplicate labels. Use label for entry at start
Dianne Hackborneb034652009-09-07 00:49:58 -0700546 mList.add(new DisplayResolveInfo(ro, roLabel, null, null));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 } else {
Adam Powellc5878612012-05-04 18:42:38 -0700548 mShowExtended = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 boolean usePkg = false;
550 CharSequence startApp = ro.activityInfo.applicationInfo.loadLabel(mPm);
551 if (startApp == null) {
552 usePkg = true;
553 }
554 if (!usePkg) {
555 // Use HashSet to track duplicates
556 HashSet<CharSequence> duplicates =
557 new HashSet<CharSequence>();
558 duplicates.add(startApp);
559 for (int j = start+1; j <= end ; j++) {
560 ResolveInfo jRi = rList.get(j);
561 CharSequence jApp = jRi.activityInfo.applicationInfo.loadLabel(mPm);
562 if ( (jApp == null) || (duplicates.contains(jApp))) {
563 usePkg = true;
564 break;
565 } else {
566 duplicates.add(jApp);
567 }
568 }
569 // Clear HashSet for later use
570 duplicates.clear();
571 }
572 for (int k = start; k <= end; k++) {
573 ResolveInfo add = rList.get(k);
574 if (usePkg) {
575 // Use application name for all entries from start to end-1
576 mList.add(new DisplayResolveInfo(add, roLabel,
Dianne Hackborneb034652009-09-07 00:49:58 -0700577 add.activityInfo.packageName, null));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 } else {
579 // Use package name for all entries from start to end-1
580 mList.add(new DisplayResolveInfo(add, roLabel,
Dianne Hackborneb034652009-09-07 00:49:58 -0700581 add.activityInfo.applicationInfo.loadLabel(mPm), null));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 }
583 }
584 }
585 }
586
587 public ResolveInfo resolveInfoForPosition(int position) {
588 if (mList == null) {
589 return null;
590 }
591
592 return mList.get(position).ri;
593 }
594
595 public Intent intentForPosition(int position) {
596 if (mList == null) {
597 return null;
598 }
599
Dianne Hackborneb034652009-09-07 00:49:58 -0700600 DisplayResolveInfo dri = mList.get(position);
601
602 Intent intent = new Intent(dri.origIntent != null
603 ? dri.origIntent : mIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
605 |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
Dianne Hackborneb034652009-09-07 00:49:58 -0700606 ActivityInfo ai = dri.ri.activityInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 intent.setComponent(new ComponentName(
608 ai.applicationInfo.packageName, ai.name));
609 return intent;
610 }
611
612 public int getCount() {
613 return mList != null ? mList.size() : 0;
614 }
615
616 public Object getItem(int position) {
617 return position;
618 }
619
620 public long getItemId(int position) {
621 return position;
622 }
623
624 public View getView(int position, View convertView, ViewGroup parent) {
625 View view;
626 if (convertView == null) {
627 view = mInflater.inflate(
628 com.android.internal.R.layout.resolve_list_item, parent, false);
Adam Powellc5878612012-05-04 18:42:38 -0700629
630 // Fix the icon size even if we have different sized resources
631 ImageView icon = (ImageView)view.findViewById(R.id.icon);
632 ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) icon.getLayoutParams();
633 lp.width = lp.height = mIconSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800634 } else {
635 view = convertView;
636 }
637 bindView(view, mList.get(position));
638 return view;
639 }
640
641 private final void bindView(View view, DisplayResolveInfo info) {
642 TextView text = (TextView)view.findViewById(com.android.internal.R.id.text1);
643 TextView text2 = (TextView)view.findViewById(com.android.internal.R.id.text2);
644 ImageView icon = (ImageView)view.findViewById(R.id.icon);
645 text.setText(info.displayLabel);
Adam Powellc5878612012-05-04 18:42:38 -0700646 if (mShowExtended) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 text2.setVisibility(View.VISIBLE);
648 text2.setText(info.extendedInfo);
649 } else {
650 text2.setVisibility(View.GONE);
651 }
Dianne Hackborneb034652009-09-07 00:49:58 -0700652 if (info.displayIcon == null) {
Adam Powellc5878612012-05-04 18:42:38 -0700653 info.displayIcon = loadIconForResolveInfo(info.ri);
Dianne Hackborneb034652009-09-07 00:49:58 -0700654 }
655 icon.setImageDrawable(info.displayIcon);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800656 }
657 }
658
Adam Powell2d809622012-03-22 15:24:43 -0700659 class ItemLongClickListener implements AdapterView.OnItemLongClickListener {
660
661 @Override
662 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
663 ResolveInfo ri = mAdapter.resolveInfoForPosition(position);
Adam Powellc5878612012-05-04 18:42:38 -0700664 showAppDetails(ri);
Adam Powell2d809622012-03-22 15:24:43 -0700665 return true;
666 }
667
668 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669}
670