| /* |
| * Copyright (C) 2007 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.settings.quicklaunch; |
| |
| import com.android.settings.R; |
| |
| import android.app.ListActivity; |
| import android.content.Intent; |
| import android.content.pm.ActivityInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ResolveInfo; |
| import android.graphics.drawable.Drawable; |
| import android.os.Bundle; |
| import android.os.Handler; |
| import android.view.Menu; |
| import android.view.MenuItem; |
| import android.view.View; |
| import android.widget.ImageView; |
| import android.widget.ListView; |
| import android.widget.SimpleAdapter; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.TreeMap; |
| |
| /** |
| * Activity to pick a bookmark that will be returned to the caller. |
| * <p> |
| * Currently, bookmarks are either: |
| * <li> Activities that are in the launcher |
| * <li> Activities that are within an app that is capable of being launched with |
| * the {@link Intent#ACTION_CREATE_SHORTCUT}. |
| */ |
| public class BookmarkPicker extends ListActivity implements SimpleAdapter.ViewBinder { |
| |
| private static final String TAG = "BookmarkPicker"; |
| |
| /** Extra in the returned intent from this activity. */ |
| public static final String EXTRA_TITLE = "com.android.settings.quicklaunch.TITLE"; |
| |
| /** Extra that should be provided, and will be returned. */ |
| public static final String EXTRA_SHORTCUT = "com.android.settings.quicklaunch.SHORTCUT"; |
| |
| /** |
| * The request code for the screen to create a bookmark that is WITHIN an |
| * application. For example, Gmail can return a bookmark for the inbox |
| * folder. |
| */ |
| private static final int REQUEST_CREATE_SHORTCUT = 1; |
| |
| /** Intent used to get all the activities that are launch-able */ |
| private static Intent sLaunchIntent; |
| /** Intent used to get all the activities that are {@link #REQUEST_CREATE_SHORTCUT}-able */ |
| private static Intent sShortcutIntent; |
| |
| /** |
| * List of ResolveInfo for activities that we can bookmark (either directly |
| * to the activity, or by launching the activity and it returning a bookmark |
| * WITHIN that application). |
| */ |
| private List<ResolveInfo> mResolveList; |
| |
| // List adapter stuff |
| private static final String KEY_TITLE = "TITLE"; |
| private static final String KEY_RESOLVE_INFO = "RESOLVE_INFO"; |
| private static final String sKeys[] = new String[] { KEY_TITLE, KEY_RESOLVE_INFO }; |
| private static final int sResourceIds[] = new int[] { R.id.title, R.id.icon }; |
| private SimpleAdapter mMyAdapter; |
| |
| /** Display those activities that are launch-able */ |
| private static final int DISPLAY_MODE_LAUNCH = 0; |
| /** Display those activities that are able to have bookmarks WITHIN the application */ |
| private static final int DISPLAY_MODE_SHORTCUT = 1; |
| private int mDisplayMode = DISPLAY_MODE_LAUNCH; |
| |
| private Handler mUiHandler = new Handler(); |
| |
| @Override |
| protected void onCreate(Bundle savedInstanceState) { |
| super.onCreate(savedInstanceState); |
| |
| updateListAndAdapter(); |
| } |
| |
| @Override |
| public boolean onCreateOptionsMenu(Menu menu) { |
| menu.add(0, DISPLAY_MODE_LAUNCH, 0, R.string.quick_launch_display_mode_applications) |
| .setIcon(com.android.internal.R.drawable.ic_menu_archive); |
| menu.add(0, DISPLAY_MODE_SHORTCUT, 0, R.string.quick_launch_display_mode_shortcuts) |
| .setIcon(com.android.internal.R.drawable.ic_menu_goto); |
| return true; |
| } |
| |
| @Override |
| public boolean onPrepareOptionsMenu(Menu menu) { |
| menu.findItem(DISPLAY_MODE_LAUNCH).setVisible(mDisplayMode != DISPLAY_MODE_LAUNCH); |
| menu.findItem(DISPLAY_MODE_SHORTCUT).setVisible(mDisplayMode != DISPLAY_MODE_SHORTCUT); |
| return true; |
| } |
| |
| @Override |
| public boolean onOptionsItemSelected(MenuItem item) { |
| |
| switch (item.getItemId()) { |
| |
| case DISPLAY_MODE_LAUNCH: |
| mDisplayMode = DISPLAY_MODE_LAUNCH; |
| break; |
| |
| case DISPLAY_MODE_SHORTCUT: |
| mDisplayMode = DISPLAY_MODE_SHORTCUT; |
| break; |
| |
| default: |
| return false; |
| } |
| |
| updateListAndAdapter(); |
| return true; |
| } |
| |
| private void ensureIntents() { |
| if (sLaunchIntent == null) { |
| sLaunchIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER); |
| sShortcutIntent = new Intent(Intent.ACTION_CREATE_SHORTCUT); |
| } |
| } |
| |
| /** |
| * This should be called from the UI thread. |
| */ |
| private void updateListAndAdapter() { |
| // Get the activities in a separate thread |
| new Thread("data updater") { |
| @Override |
| public void run() { |
| synchronized (BookmarkPicker.this) { |
| /* |
| * Don't touch any of the lists that are being used by the |
| * adapter in this thread! |
| */ |
| ArrayList<ResolveInfo> newResolveList = new ArrayList<ResolveInfo>(); |
| ArrayList<Map<String, ?>> newAdapterList = new ArrayList<Map<String, ?>>(); |
| |
| fillResolveList(newResolveList); |
| Collections.sort(newResolveList, |
| new ResolveInfo.DisplayNameComparator(getPackageManager())); |
| |
| fillAdapterList(newAdapterList, newResolveList); |
| |
| updateAdapterToUseNewLists(newAdapterList, newResolveList); |
| } |
| } |
| }.start(); |
| } |
| |
| private void updateAdapterToUseNewLists(final ArrayList<Map<String, ?>> newAdapterList, |
| final ArrayList<ResolveInfo> newResolveList) { |
| // Post this back on the UI thread |
| mUiHandler.post(new Runnable() { |
| public void run() { |
| /* |
| * SimpleAdapter does not support changing the lists after it |
| * has been created. We just create a new instance. |
| */ |
| mMyAdapter = createResolveAdapter(newAdapterList); |
| mResolveList = newResolveList; |
| setListAdapter(mMyAdapter); |
| } |
| }); |
| } |
| |
| /** |
| * Gets all activities matching our current display mode. |
| * |
| * @param list The list to fill. |
| */ |
| private void fillResolveList(List<ResolveInfo> list) { |
| ensureIntents(); |
| PackageManager pm = getPackageManager(); |
| list.clear(); |
| |
| if (mDisplayMode == DISPLAY_MODE_LAUNCH) { |
| list.addAll(pm.queryIntentActivities(sLaunchIntent, 0)); |
| } else if (mDisplayMode == DISPLAY_MODE_SHORTCUT) { |
| list.addAll(pm.queryIntentActivities(sShortcutIntent, 0)); |
| } |
| } |
| |
| private SimpleAdapter createResolveAdapter(List<Map<String, ?>> list) { |
| SimpleAdapter adapter = new SimpleAdapter(this, list, |
| R.layout.bookmark_picker_item, sKeys, sResourceIds); |
| adapter.setViewBinder(this); |
| return adapter; |
| } |
| |
| private void fillAdapterList(List<Map<String, ?>> list, |
| List<ResolveInfo> resolveList) { |
| list.clear(); |
| int resolveListSize = resolveList.size(); |
| for (int i = 0; i < resolveListSize; i++) { |
| ResolveInfo info = resolveList.get(i); |
| /* |
| * Simple adapter craziness. For each item, we need to create a map |
| * from a key to its value (the value can be any object--the view |
| * binder will take care of filling the View with a representation |
| * of that object). |
| */ |
| Map<String, Object> map = new TreeMap<String, Object>(); |
| map.put(KEY_TITLE, getResolveInfoTitle(info)); |
| map.put(KEY_RESOLVE_INFO, info); |
| list.add(map); |
| } |
| } |
| |
| /** Get the title for a resolve info. */ |
| private String getResolveInfoTitle(ResolveInfo info) { |
| CharSequence label = info.loadLabel(getPackageManager()); |
| if (label == null) label = info.activityInfo.name; |
| return label != null ? label.toString() : null; |
| } |
| |
| @Override |
| protected void onListItemClick(ListView l, View v, int position, long id) { |
| if (position >= mResolveList.size()) return; |
| |
| ResolveInfo info = mResolveList.get(position); |
| |
| switch (mDisplayMode) { |
| |
| case DISPLAY_MODE_LAUNCH: |
| // We can go ahead and return the clicked info's intent |
| Intent intent = getIntentForResolveInfo(info, Intent.ACTION_MAIN); |
| intent.addCategory(Intent.CATEGORY_LAUNCHER); |
| finish(intent, getResolveInfoTitle(info)); |
| break; |
| |
| case DISPLAY_MODE_SHORTCUT: |
| // Start the shortcut activity so the user can pick the actual intent |
| // (example: Gmail's shortcut activity shows a list of mailboxes) |
| startShortcutActivity(info); |
| break; |
| } |
| |
| } |
| |
| private static Intent getIntentForResolveInfo(ResolveInfo info, String action) { |
| Intent intent = new Intent(action); |
| ActivityInfo ai = info.activityInfo; |
| intent.setClassName(ai.packageName, ai.name); |
| return intent; |
| } |
| |
| /** |
| * Starts an activity to get a shortcut. |
| * <p> |
| * For example, Gmail has an activity that lists the available labels. It |
| * returns a shortcut intent for going directly to this label. |
| */ |
| private void startShortcutActivity(ResolveInfo info) { |
| Intent intent = getIntentForResolveInfo(info, Intent.ACTION_CREATE_SHORTCUT); |
| startActivityForResult(intent, REQUEST_CREATE_SHORTCUT); |
| |
| // Will get a callback to onActivityResult |
| } |
| |
| @Override |
| protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
| if (resultCode != RESULT_OK) { |
| return; |
| } |
| |
| switch (requestCode) { |
| |
| case REQUEST_CREATE_SHORTCUT: |
| if (data != null) { |
| finish((Intent) data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT), |
| data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME)); |
| } |
| break; |
| |
| default: |
| super.onActivityResult(requestCode, resultCode, data); |
| break; |
| } |
| } |
| |
| /** |
| * Finishes the activity and returns the given data. |
| */ |
| private void finish(Intent intent, String title) { |
| // Give back what was given to us (it will have the shortcut, for example) |
| intent.putExtras(getIntent()); |
| // Put our information |
| intent.putExtra(EXTRA_TITLE, title); |
| setResult(RESULT_OK, intent); |
| finish(); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean setViewValue(View view, Object data, String textRepresentation) { |
| if (view.getId() == R.id.icon) { |
| Drawable icon = ((ResolveInfo) data).loadIcon(getPackageManager()); |
| if (icon != null) { |
| ((ImageView) view).setImageDrawable(icon); |
| } |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| } |