blob: c22cd2646124892dc195f3a4df10ddc92eb21ec4 [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.RemoteException;
Dianne Hackbornf02b60a2012-08-16 10:48:27 -070039import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.util.Log;
Adam Powell2d809622012-03-22 15:24:43 -070041import android.view.LayoutInflater;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.view.View;
43import android.view.ViewGroup;
Adam Powell2d809622012-03-22 15:24:43 -070044import android.widget.AdapterView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.widget.BaseAdapter;
Adam Powellc5878612012-05-04 18:42:38 -070046import android.widget.Button;
47import android.widget.GridView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.widget.ImageView;
Adam Powell2d809622012-03-22 15:24:43 -070049import android.widget.ListView;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.widget.TextView;
Adam Powell2d809622012-03-22 15:24:43 -070051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import java.util.ArrayList;
53import java.util.Collections;
54import java.util.HashSet;
55import java.util.Iterator;
56import java.util.List;
57import java.util.Set;
58
59/**
60 * This activity is displayed when the system attempts to start an Intent for
61 * which there is more than one matching activity, allowing the user to decide
62 * which to go to. It is not normally used directly by application developers.
63 */
Adam Powellc5878612012-05-04 18:42:38 -070064public class ResolverActivity extends AlertActivity implements AdapterView.OnItemClickListener {
65 private static final String TAG = "ResolverActivity";
You Kim43a5070e2012-11-21 23:23:45 +090066 private static final boolean DEBUG = false;
Adam Powellc5878612012-05-04 18:42:38 -070067
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;
Adam Powelld81cc4a2012-07-19 13:51:39 -070079 private int mLastSelected = GridView.INVALID_POSITION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080
Dianne Hackbornd44713a2012-04-30 16:34:46 -070081 private boolean mRegistered;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -080082 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
83 @Override public void onSomePackagesChanged() {
84 mAdapter.handlePackagesChanged();
85 }
86 };
87
Dianne Hackborn905577f2011-09-07 18:31:28 -070088 private Intent makeMyIntent() {
89 Intent intent = new Intent(getIntent());
90 // The resolver activity is set to be hidden from recent tasks.
91 // we don't want this attribute to be propagated to the next activity
92 // being launched. Note that if the original Intent also had this
93 // flag set, we are now losing it. That should be a very rare case
94 // and we can live with this.
95 intent.setFlags(intent.getFlags()&~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
96 return intent;
97 }
98
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 @Override
100 protected void onCreate(Bundle savedInstanceState) {
Dianne Hackborn905577f2011-09-07 18:31:28 -0700101 onCreate(savedInstanceState, makeMyIntent(),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 getResources().getText(com.android.internal.R.string.whichApplication),
Jeff Hamiltond88e9aa2011-01-24 14:53:00 -0600103 null, null, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104 }
105
106 protected void onCreate(Bundle savedInstanceState, Intent intent,
Jeff Hamiltond88e9aa2011-01-24 14:53:00 -0600107 CharSequence title, Intent[] initialIntents, List<ResolveInfo> rList,
Mike Lockwoodbce6f8f2011-03-13 17:26:52 -0400108 boolean alwaysUseOption) {
Adam Powellc5878612012-05-04 18:42:38 -0700109 setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 super.onCreate(savedInstanceState);
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700111 try {
112 mLaunchedFromUid = ActivityManagerNative.getDefault().getLaunchedFromUid(
113 getActivityToken());
114 } catch (RemoteException e) {
115 mLaunchedFromUid = -1;
116 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 mPm = getPackageManager();
Adam Powellc5878612012-05-04 18:42:38 -0700118 mAlwaysUseOption = alwaysUseOption;
Adam Powell589e6f92012-05-06 20:52:38 -0700119 mMaxColumns = getResources().getInteger(R.integer.config_maxResolverActivityColumns);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120 intent.setComponent(null);
121
122 AlertController.AlertParams ap = mAlertParams;
123
124 ap.mTitle = title;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700126 mPackageMonitor.register(this, getMainLooper(), false);
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700127 mRegistered = true;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800128
Adam Powellc5878612012-05-04 18:42:38 -0700129 final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
130 mIconDpi = am.getLauncherLargeIconDensity();
131 mIconSize = am.getLauncherLargeIconSize();
132
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700133 mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList,
134 mLaunchedFromUid);
Mike Lockwood02eb8742011-02-27 09:10:37 -0800135 int count = mAdapter.getCount();
Dianne Hackbornf02b60a2012-08-16 10:48:27 -0700136 if (mLaunchedFromUid < 0 || UserHandle.isIsolated(mLaunchedFromUid)) {
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700137 // Gulp!
138 finish();
139 return;
140 } else if (count > 1) {
Adam Powellc5878612012-05-04 18:42:38 -0700141 ap.mView = getLayoutInflater().inflate(R.layout.resolver_grid, null);
142 mGrid = (GridView) ap.mView.findViewById(R.id.resolver_grid);
143 mGrid.setAdapter(mAdapter);
144 mGrid.setOnItemClickListener(this);
145 mGrid.setOnItemLongClickListener(new ItemLongClickListener());
146
147 if (alwaysUseOption) {
148 mGrid.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
149 }
150
151 resizeGrid();
Mike Lockwood02eb8742011-02-27 09:10:37 -0800152 } else if (count == 1) {
Amith Yamasani203a2f42012-10-03 20:16:40 -0700153 startActivity(mAdapter.intentForPosition(0));
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700154 mPackageMonitor.unregister();
155 mRegistered = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 finish();
157 return;
158 } else {
Adam Powellc5878612012-05-04 18:42:38 -0700159 ap.mMessage = getResources().getText(R.string.noApplications);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 }
161
162 setupAlert();
Adam Powell2d809622012-03-22 15:24:43 -0700163
Adam Powellc5878612012-05-04 18:42:38 -0700164 if (alwaysUseOption) {
165 final ViewGroup buttonLayout = (ViewGroup) findViewById(R.id.button_bar);
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700166 if (buttonLayout != null) {
167 buttonLayout.setVisibility(View.VISIBLE);
168 mAlwaysButton = (Button) buttonLayout.findViewById(R.id.button_always);
169 mOnceButton = (Button) buttonLayout.findViewById(R.id.button_once);
170 } else {
171 mAlwaysUseOption = false;
172 }
Adam Powell2d809622012-03-22 15:24:43 -0700173 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 }
175
Adam Powellc5878612012-05-04 18:42:38 -0700176 void resizeGrid() {
177 final int itemCount = mAdapter.getCount();
Adam Powell589e6f92012-05-06 20:52:38 -0700178 mGrid.setNumColumns(Math.min(itemCount, mMaxColumns));
Adam Powellc5878612012-05-04 18:42:38 -0700179 }
180
181 Drawable getIcon(Resources res, int resId) {
182 Drawable result;
183 try {
184 result = res.getDrawableForDensity(resId, mIconDpi);
185 } catch (Resources.NotFoundException e) {
186 result = null;
187 }
188
189 return result;
190 }
191
192 Drawable loadIconForResolveInfo(ResolveInfo ri) {
193 Drawable dr;
194 try {
195 if (ri.resolvePackageName != null && ri.icon != 0) {
196 dr = getIcon(mPm.getResourcesForApplication(ri.resolvePackageName), ri.icon);
197 if (dr != null) {
198 return dr;
199 }
200 }
201 final int iconRes = ri.getIconResource();
202 if (iconRes != 0) {
203 dr = getIcon(mPm.getResourcesForApplication(ri.activityInfo.packageName), iconRes);
204 if (dr != null) {
205 return dr;
206 }
207 }
208 } catch (NameNotFoundException e) {
209 Log.e(TAG, "Couldn't find resources for package", e);
210 }
211 return ri.loadIcon(mPm);
212 }
213
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800214 @Override
215 protected void onRestart() {
216 super.onRestart();
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700217 if (!mRegistered) {
218 mPackageMonitor.register(this, getMainLooper(), false);
219 mRegistered = true;
220 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800221 mAdapter.handlePackagesChanged();
222 }
223
224 @Override
225 protected void onStop() {
226 super.onStop();
Dianne Hackbornd44713a2012-04-30 16:34:46 -0700227 if (mRegistered) {
228 mPackageMonitor.unregister();
229 mRegistered = false;
230 }
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700231 if ((getIntent().getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
232 // This resolver is in the unusual situation where it has been
233 // launched at the top of a new task. We don't let it be added
234 // to the recent tasks shown to the user, and we need to make sure
235 // that each time we are launched we get the correct launching
236 // uid (not re-using the same resolver from an old launching uid),
237 // so we will now finish ourself since being no longer visible,
238 // the user probably can't get back to us.
239 if (!isChangingConfigurations()) {
240 finish();
241 }
242 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800243 }
244
Adam Powellc5878612012-05-04 18:42:38 -0700245 @Override
Adam Powell9bee4662012-05-08 11:07:23 -0700246 protected void onRestoreInstanceState(Bundle savedInstanceState) {
247 super.onRestoreInstanceState(savedInstanceState);
248 if (mAlwaysUseOption) {
249 final int checkedPos = mGrid.getCheckedItemPosition();
250 final boolean enabled = checkedPos != GridView.INVALID_POSITION;
Adam Powelld81cc4a2012-07-19 13:51:39 -0700251 mLastSelected = checkedPos;
Adam Powell9bee4662012-05-08 11:07:23 -0700252 mAlwaysButton.setEnabled(enabled);
253 mOnceButton.setEnabled(enabled);
254 if (enabled) {
255 mGrid.setSelection(checkedPos);
256 }
257 }
258 }
259
260 @Override
Adam Powellc5878612012-05-04 18:42:38 -0700261 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Adam Powelld81cc4a2012-07-19 13:51:39 -0700262 final int checkedPos = mGrid.getCheckedItemPosition();
263 final boolean hasValidSelection = checkedPos != GridView.INVALID_POSITION;
Adam Powellbdda4e72012-07-20 11:22:03 -0700264 if (mAlwaysUseOption && (!hasValidSelection || mLastSelected != checkedPos)) {
Adam Powelld81cc4a2012-07-19 13:51:39 -0700265 mAlwaysButton.setEnabled(hasValidSelection);
266 mOnceButton.setEnabled(hasValidSelection);
267 if (hasValidSelection) {
Adam Powell9bee4662012-05-08 11:07:23 -0700268 mGrid.smoothScrollToPosition(checkedPos);
269 }
Adam Powelld81cc4a2012-07-19 13:51:39 -0700270 mLastSelected = checkedPos;
Adam Powellc5878612012-05-04 18:42:38 -0700271 } else {
272 startSelected(position, false);
273 }
274 }
275
276 public void onButtonClick(View v) {
277 final int id = v.getId();
278 startSelected(mGrid.getCheckedItemPosition(), id == R.id.button_always);
279 dismiss();
280 }
281
282 void startSelected(int which, boolean always) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 ResolveInfo ri = mAdapter.resolveInfoForPosition(which);
284 Intent intent = mAdapter.intentForPosition(which);
Adam Powellc5878612012-05-04 18:42:38 -0700285 onIntentSelected(ri, intent, always);
Mike Lockwood02eb8742011-02-27 09:10:37 -0800286 finish();
287 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800288
Mike Lockwood02eb8742011-02-27 09:10:37 -0800289 protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
290 if (alwaysCheck) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800291 // Build a reasonable intent filter, based on what matched.
292 IntentFilter filter = new IntentFilter();
293
294 if (intent.getAction() != null) {
295 filter.addAction(intent.getAction());
296 }
297 Set<String> categories = intent.getCategories();
298 if (categories != null) {
299 for (String cat : categories) {
300 filter.addCategory(cat);
301 }
302 }
303 filter.addCategory(Intent.CATEGORY_DEFAULT);
304
305 int cat = ri.match&IntentFilter.MATCH_CATEGORY_MASK;
306 Uri data = intent.getData();
307 if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
308 String mimeType = intent.resolveType(this);
309 if (mimeType != null) {
310 try {
311 filter.addDataType(mimeType);
312 } catch (IntentFilter.MalformedMimeTypeException e) {
313 Log.w("ResolverActivity", e);
314 filter = null;
315 }
316 }
Dianne Hackborn5ef402b2010-03-26 17:17:25 -0700317 }
318 if (data != null && data.getScheme() != null) {
319 // We need the data specification if there was no type,
320 // OR if the scheme is not one of our magical "file:"
321 // or "content:" schemes (see IntentFilter for the reason).
322 if (cat != IntentFilter.MATCH_CATEGORY_TYPE
323 || (!"file".equals(data.getScheme())
324 && !"content".equals(data.getScheme()))) {
325 filter.addDataScheme(data.getScheme());
You Kim43a5070e2012-11-21 23:23:45 +0900326
Dianne Hackborn5ef402b2010-03-26 17:17:25 -0700327 // Look through the resolved filter to determine which part
328 // of it matched the original Intent.
329 Iterator<IntentFilter.AuthorityEntry> aIt = ri.filter.authoritiesIterator();
330 if (aIt != null) {
331 while (aIt.hasNext()) {
332 IntentFilter.AuthorityEntry a = aIt.next();
333 if (a.match(data) >= 0) {
334 int port = a.getPort();
335 filter.addDataAuthority(a.getHost(),
336 port >= 0 ? Integer.toString(port) : null);
337 break;
338 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 }
340 }
Dianne Hackborn5ef402b2010-03-26 17:17:25 -0700341 Iterator<PatternMatcher> pIt = ri.filter.pathsIterator();
342 if (pIt != null) {
343 String path = data.getPath();
344 while (path != null && pIt.hasNext()) {
345 PatternMatcher p = pIt.next();
346 if (p.match(path)) {
347 filter.addDataPath(p.getPath(), p.getType());
348 break;
349 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 }
351 }
352 }
353 }
354
355 if (filter != null) {
356 final int N = mAdapter.mList.size();
357 ComponentName[] set = new ComponentName[N];
358 int bestMatch = 0;
359 for (int i=0; i<N; i++) {
360 ResolveInfo r = mAdapter.mList.get(i).ri;
361 set[i] = new ComponentName(r.activityInfo.packageName,
362 r.activityInfo.name);
363 if (r.match > bestMatch) bestMatch = r.match;
364 }
365 getPackageManager().addPreferredActivity(filter, bestMatch, set,
Amith Yamasani203a2f42012-10-03 20:16:40 -0700366 intent.getComponent());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800367 }
368 }
369
370 if (intent != null) {
Amith Yamasani203a2f42012-10-03 20:16:40 -0700371 startActivity(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800372 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 }
374
Adam Powellc5878612012-05-04 18:42:38 -0700375 void showAppDetails(ResolveInfo ri) {
376 Intent in = new Intent().setAction("android.settings.APPLICATION_DETAILS_SETTINGS")
Adam Powell0fc5b2b2012-07-18 18:20:29 -0700377 .setData(Uri.fromParts("package", ri.activityInfo.packageName, null))
378 .addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
Amith Yamasani203a2f42012-10-03 20:16:40 -0700379 startActivity(in);
Adam Powellc5878612012-05-04 18:42:38 -0700380 }
381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 private final class DisplayResolveInfo {
383 ResolveInfo ri;
384 CharSequence displayLabel;
Dianne Hackborneb034652009-09-07 00:49:58 -0700385 Drawable displayIcon;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800386 CharSequence extendedInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -0700387 Intent origIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800388
Dianne Hackborneb034652009-09-07 00:49:58 -0700389 DisplayResolveInfo(ResolveInfo pri, CharSequence pLabel,
390 CharSequence pInfo, Intent pOrigIntent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 ri = pri;
392 displayLabel = pLabel;
393 extendedInfo = pInfo;
Dianne Hackborneb034652009-09-07 00:49:58 -0700394 origIntent = pOrigIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 }
396 }
397
398 private final class ResolveListAdapter extends BaseAdapter {
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800399 private final Intent[] mInitialIntents;
400 private final List<ResolveInfo> mBaseResolveList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 private final Intent mIntent;
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700402 private final int mLaunchedFromUid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 private final LayoutInflater mInflater;
404
405 private List<DisplayResolveInfo> mList;
406
Dianne Hackborneb034652009-09-07 00:49:58 -0700407 public ResolveListAdapter(Context context, Intent intent,
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700408 Intent[] initialIntents, List<ResolveInfo> rList, int launchedFromUid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800409 mIntent = new Intent(intent);
410 mIntent.setComponent(null);
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800411 mInitialIntents = initialIntents;
412 mBaseResolveList = rList;
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700413 mLaunchedFromUid = launchedFromUid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800414 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
You Kim43a5070e2012-11-21 23:23:45 +0900415 mList = new ArrayList<DisplayResolveInfo>();
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800416 rebuildList();
417 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800419 public void handlePackagesChanged() {
Adam Powellc5878612012-05-04 18:42:38 -0700420 final int oldItemCount = getCount();
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800421 rebuildList();
422 notifyDataSetChanged();
You Kim43a5070e2012-11-21 23:23:45 +0900423 final int newItemCount = getCount();
424 if (newItemCount == 0) {
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800425 // We no longer have any items... just finish the activity.
426 finish();
You Kim43a5070e2012-11-21 23:23:45 +0900427 } else if (newItemCount != oldItemCount) {
Adam Powellc5878612012-05-04 18:42:38 -0700428 resizeGrid();
429 }
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800430 }
431
432 private void rebuildList() {
You Kim43a5070e2012-11-21 23:23:45 +0900433 List<ResolveInfo> currentResolveList;
434
435 mList.clear();
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800436 if (mBaseResolveList != null) {
You Kim43a5070e2012-11-21 23:23:45 +0900437 currentResolveList = mBaseResolveList;
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800438 } else {
You Kim43a5070e2012-11-21 23:23:45 +0900439 currentResolveList = mPm.queryIntentActivities(
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800440 mIntent, PackageManager.MATCH_DEFAULT_ONLY
Amith Yamasani203a2f42012-10-03 20:16:40 -0700441 | (mAlwaysUseOption ? PackageManager.GET_RESOLVED_FILTER : 0));
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700442 // Filter out any activities that the launched uid does not
443 // have permission for. We don't do this when we have an explicit
444 // list of resolved activities, because that only happens when
445 // we are being subclassed, so we can safely launch whatever
446 // they gave us.
You Kim43a5070e2012-11-21 23:23:45 +0900447 if (currentResolveList != null) {
448 for (int i=currentResolveList.size()-1; i >= 0; i--) {
449 ActivityInfo ai = currentResolveList.get(i).activityInfo;
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700450 int granted = ActivityManager.checkComponentPermission(
451 ai.permission, mLaunchedFromUid,
452 ai.applicationInfo.uid, ai.exported);
453 if (granted != PackageManager.PERMISSION_GRANTED) {
454 // Access not allowed!
You Kim43a5070e2012-11-21 23:23:45 +0900455 currentResolveList.remove(i);
Dianne Hackborn5320eb82012-05-18 12:05:04 -0700456 }
457 }
458 }
Jeff Hamiltond88e9aa2011-01-24 14:53:00 -0600459 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800460 int N;
You Kim43a5070e2012-11-21 23:23:45 +0900461 if ((currentResolveList != null) && ((N = currentResolveList.size()) > 0)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800462 // Only display the first matches that are either of equal
463 // priority or have asked to be default options.
You Kim43a5070e2012-11-21 23:23:45 +0900464 ResolveInfo r0 = currentResolveList.get(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 for (int i=1; i<N; i++) {
You Kim43a5070e2012-11-21 23:23:45 +0900466 ResolveInfo ri = currentResolveList.get(i);
467 if (DEBUG) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 "ResolveListActivity",
469 r0.activityInfo.name + "=" +
470 r0.priority + "/" + r0.isDefault + " vs " +
471 ri.activityInfo.name + "=" +
472 ri.priority + "/" + ri.isDefault);
You Kim43a5070e2012-11-21 23:23:45 +0900473 if (r0.priority != ri.priority ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 r0.isDefault != ri.isDefault) {
475 while (i < N) {
You Kim43a5070e2012-11-21 23:23:45 +0900476 currentResolveList.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 N--;
478 }
479 }
480 }
481 if (N > 1) {
482 ResolveInfo.DisplayNameComparator rComparator =
483 new ResolveInfo.DisplayNameComparator(mPm);
You Kim43a5070e2012-11-21 23:23:45 +0900484 Collections.sort(currentResolveList, rComparator);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 }
Dianne Hackborneb034652009-09-07 00:49:58 -0700486 // First put the initial items at the top.
Dianne Hackborne8f2c7f2012-03-01 17:30:53 -0800487 if (mInitialIntents != null) {
488 for (int i=0; i<mInitialIntents.length; i++) {
489 Intent ii = mInitialIntents[i];
Dianne Hackborneb034652009-09-07 00:49:58 -0700490 if (ii == null) {
491 continue;
492 }
493 ActivityInfo ai = ii.resolveActivityInfo(
494 getPackageManager(), 0);
495 if (ai == null) {
496 Log.w("ResolverActivity", "No activity found for "
497 + ii);
498 continue;
499 }
500 ResolveInfo ri = new ResolveInfo();
501 ri.activityInfo = ai;
502 if (ii instanceof LabeledIntent) {
503 LabeledIntent li = (LabeledIntent)ii;
504 ri.resolvePackageName = li.getSourcePackage();
505 ri.labelRes = li.getLabelResource();
506 ri.nonLocalizedLabel = li.getNonLocalizedLabel();
507 ri.icon = li.getIconResource();
508 }
509 mList.add(new DisplayResolveInfo(ri,
510 ri.loadLabel(getPackageManager()), null, ii));
511 }
512 }
You Kim43a5070e2012-11-21 23:23:45 +0900513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800514 // Check for applications with same name and use application name or
515 // package name if necessary
You Kim43a5070e2012-11-21 23:23:45 +0900516 r0 = currentResolveList.get(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517 int start = 0;
518 CharSequence r0Label = r0.loadLabel(mPm);
Adam Powellc5878612012-05-04 18:42:38 -0700519 mShowExtended = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 for (int i = 1; i < N; i++) {
521 if (r0Label == null) {
522 r0Label = r0.activityInfo.packageName;
523 }
You Kim43a5070e2012-11-21 23:23:45 +0900524 ResolveInfo ri = currentResolveList.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 CharSequence riLabel = ri.loadLabel(mPm);
526 if (riLabel == null) {
527 riLabel = ri.activityInfo.packageName;
528 }
529 if (riLabel.equals(r0Label)) {
530 continue;
531 }
You Kim43a5070e2012-11-21 23:23:45 +0900532 processGroup(currentResolveList, start, (i-1), r0, r0Label);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800533 r0 = ri;
534 r0Label = riLabel;
535 start = i;
536 }
537 // Process last group
You Kim43a5070e2012-11-21 23:23:45 +0900538 processGroup(currentResolveList, start, (N-1), r0, r0Label);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 }
540 }
541
542 private void processGroup(List<ResolveInfo> rList, int start, int end, ResolveInfo ro,
543 CharSequence roLabel) {
544 // Process labels from start to i
545 int num = end - start+1;
546 if (num == 1) {
547 // No duplicate labels. Use label for entry at start
Dianne Hackborneb034652009-09-07 00:49:58 -0700548 mList.add(new DisplayResolveInfo(ro, roLabel, null, null));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 } else {
Adam Powellc5878612012-05-04 18:42:38 -0700550 mShowExtended = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 boolean usePkg = false;
552 CharSequence startApp = ro.activityInfo.applicationInfo.loadLabel(mPm);
553 if (startApp == null) {
554 usePkg = true;
555 }
556 if (!usePkg) {
557 // Use HashSet to track duplicates
558 HashSet<CharSequence> duplicates =
559 new HashSet<CharSequence>();
560 duplicates.add(startApp);
561 for (int j = start+1; j <= end ; j++) {
562 ResolveInfo jRi = rList.get(j);
563 CharSequence jApp = jRi.activityInfo.applicationInfo.loadLabel(mPm);
564 if ( (jApp == null) || (duplicates.contains(jApp))) {
565 usePkg = true;
566 break;
567 } else {
568 duplicates.add(jApp);
569 }
570 }
571 // Clear HashSet for later use
572 duplicates.clear();
573 }
574 for (int k = start; k <= end; k++) {
575 ResolveInfo add = rList.get(k);
576 if (usePkg) {
577 // Use application name for all entries from start to end-1
578 mList.add(new DisplayResolveInfo(add, roLabel,
Dianne Hackborneb034652009-09-07 00:49:58 -0700579 add.activityInfo.packageName, null));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 } else {
581 // Use package name for all entries from start to end-1
582 mList.add(new DisplayResolveInfo(add, roLabel,
Dianne Hackborneb034652009-09-07 00:49:58 -0700583 add.activityInfo.applicationInfo.loadLabel(mPm), null));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 }
585 }
586 }
587 }
588
589 public ResolveInfo resolveInfoForPosition(int position) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 return mList.get(position).ri;
591 }
592
593 public Intent intentForPosition(int position) {
Dianne Hackborneb034652009-09-07 00:49:58 -0700594 DisplayResolveInfo dri = mList.get(position);
595
596 Intent intent = new Intent(dri.origIntent != null
597 ? dri.origIntent : mIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT
599 |Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP);
Dianne Hackborneb034652009-09-07 00:49:58 -0700600 ActivityInfo ai = dri.ri.activityInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 intent.setComponent(new ComponentName(
602 ai.applicationInfo.packageName, ai.name));
603 return intent;
604 }
605
606 public int getCount() {
You Kim43a5070e2012-11-21 23:23:45 +0900607 return mList.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 }
609
610 public Object getItem(int position) {
You Kim43a5070e2012-11-21 23:23:45 +0900611 return mList.get(position);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 }
613
614 public long getItemId(int position) {
615 return position;
616 }
617
618 public View getView(int position, View convertView, ViewGroup parent) {
619 View view;
620 if (convertView == null) {
621 view = mInflater.inflate(
622 com.android.internal.R.layout.resolve_list_item, parent, false);
Adam Powellc5878612012-05-04 18:42:38 -0700623
624 // Fix the icon size even if we have different sized resources
625 ImageView icon = (ImageView)view.findViewById(R.id.icon);
626 ViewGroup.LayoutParams lp = (ViewGroup.LayoutParams) icon.getLayoutParams();
627 lp.width = lp.height = mIconSize;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 } else {
629 view = convertView;
630 }
631 bindView(view, mList.get(position));
632 return view;
633 }
634
635 private final void bindView(View view, DisplayResolveInfo info) {
636 TextView text = (TextView)view.findViewById(com.android.internal.R.id.text1);
637 TextView text2 = (TextView)view.findViewById(com.android.internal.R.id.text2);
638 ImageView icon = (ImageView)view.findViewById(R.id.icon);
639 text.setText(info.displayLabel);
Adam Powellc5878612012-05-04 18:42:38 -0700640 if (mShowExtended) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 text2.setVisibility(View.VISIBLE);
642 text2.setText(info.extendedInfo);
643 } else {
644 text2.setVisibility(View.GONE);
645 }
Dianne Hackborneb034652009-09-07 00:49:58 -0700646 if (info.displayIcon == null) {
Adam Powellc5878612012-05-04 18:42:38 -0700647 info.displayIcon = loadIconForResolveInfo(info.ri);
Dianne Hackborneb034652009-09-07 00:49:58 -0700648 }
649 icon.setImageDrawable(info.displayIcon);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 }
651 }
652
Adam Powell2d809622012-03-22 15:24:43 -0700653 class ItemLongClickListener implements AdapterView.OnItemLongClickListener {
654
655 @Override
656 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
657 ResolveInfo ri = mAdapter.resolveInfoForPosition(position);
Adam Powellc5878612012-05-04 18:42:38 -0700658 showAppDetails(ri);
Adam Powell2d809622012-03-22 15:24:43 -0700659 return true;
660 }
661
662 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800663}
664