AppChooserActivity.java revision 78976de08ad5d5f9d5fcba28f3ea82350907a782
1/* 2 * Copyright (C) 2013 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.nfc.cardemulation; 18 19import com.android.internal.R; 20import com.android.internal.app.AlertActivity; 21import com.android.internal.app.AlertController; 22 23import java.util.ArrayList; 24import java.util.List; 25 26import android.app.ActivityManager; 27import android.content.ComponentName; 28import android.content.Context; 29import android.content.Intent; 30import android.content.pm.ApplicationInfo; 31import android.content.pm.PackageManager; 32import android.content.pm.PackageManager.NameNotFoundException; 33import android.graphics.drawable.Drawable; 34import android.nfc.NfcAdapter; 35import android.nfc.cardemulation.CardEmulationManager; 36import android.os.Bundle; 37import android.util.Log; 38import android.view.LayoutInflater; 39import android.view.View; 40import android.view.ViewGroup; 41import android.widget.AdapterView; 42import android.widget.BaseAdapter; 43import android.widget.ImageView; 44import android.widget.ListView; 45import android.widget.TextView; 46 47public class AppChooserActivity extends AlertActivity 48 implements AdapterView.OnItemClickListener { 49 50 static final String TAG = "AppChooserActivity"; 51 52 public static final String EXTRA_COMPONENTS = "components"; 53 public static final String EXTRA_CATEGORY = "category"; 54 public static final String EXTRA_FAILED_COMPONENT = "failed_component"; 55 56 private int mIconSize; 57 private ListView mListView; 58 private ListAdapter mListAdapter; 59 private CardEmulationManager mCardEmuManager; 60 private String mCategory; 61 62 protected void onCreate(Bundle savedInstanceState, String category, 63 ArrayList<ComponentName> options, ComponentName failedComponent) { 64 setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert); 65 super.onCreate(savedInstanceState); 66 67 if ((options == null || options.size() == 0) && failedComponent == null) { 68 Log.e(TAG, "No components passed in."); 69 finish(); 70 return; 71 } 72 73 mCategory = category; 74 75 final NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this); 76 mCardEmuManager = CardEmulationManager.getInstance(adapter); 77 AlertController.AlertParams ap = mAlertParams; 78 79 final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE); 80 mIconSize = am.getLauncherLargeIconSize(); 81 82 // Three cases: 83 // 1. Failed component and no alternatives: just an OK box 84 // 2. Failed component and alternatives: pick alternative 85 // 3. No failed component and alternatives: pick alternative 86 PackageManager pm = getPackageManager(); 87 88 CharSequence applicationLabel = "unknown"; 89 if (failedComponent != null) { 90 try { 91 ApplicationInfo info = pm.getApplicationInfo(failedComponent.getPackageName(), 0); 92 applicationLabel = info.loadLabel(pm); 93 } catch (NameNotFoundException e) { 94 } 95 96 } 97 if (options.size() == 0 && failedComponent != null) { 98 ap.mTitle = ""; 99 ap.mMessage = "This transaction couldn't be completed with " + applicationLabel + "."; 100 ap.mPositiveButtonText = "OK"; 101 setupAlert(); 102 } else { 103 mListAdapter = new ListAdapter(this, options); 104 if (failedComponent != null) { 105 ap.mTitle = "Couldn't use " + applicationLabel + "."; 106 } else { 107 if (CardEmulationManager.CATEGORY_PAYMENT.equals(category)) { 108 ap.mTitle = "Pay with"; 109 } else { 110 ap.mTitle = "Complete tap with"; 111 } 112 } 113 ap.mView = getLayoutInflater().inflate(com.android.nfc.R.layout.cardemu_resolver, null); 114 115 mListView = (ListView) ap.mView.findViewById(com.android.nfc.R.id.resolver_list); 116 mListView.setAdapter(mListAdapter); 117 mListView.setOnItemClickListener(this); 118 119 setupAlert(); 120 } 121 } 122 123 @Override 124 protected void onCreate(Bundle savedInstanceState) { 125 Intent intent = getIntent(); 126 ArrayList<ComponentName> components = intent.getParcelableArrayListExtra(EXTRA_COMPONENTS); 127 String category = intent.getStringExtra(EXTRA_CATEGORY); 128 ComponentName failedComponent = intent.getParcelableExtra(EXTRA_FAILED_COMPONENT); 129 onCreate(savedInstanceState, category, components, failedComponent); 130 } 131 132 @Override 133 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 134 DisplayAppInfo info = (DisplayAppInfo) mListAdapter.getItem(position); 135 mCardEmuManager.setDefaultForNextTap(info.component); 136 Intent dialogIntent = new Intent(this, TapAgainDialog.class); 137 dialogIntent.putExtra(TapAgainDialog.EXTRA_CATEGORY, mCategory); 138 dialogIntent.putExtra(TapAgainDialog.EXTRA_COMPONENT, info.component); 139 startActivity(dialogIntent); 140 finish(); 141 } 142 143 final class DisplayAppInfo { 144 ComponentName component; 145 CharSequence displayLabel; 146 Drawable displayIcon; 147 148 public DisplayAppInfo(ComponentName component, CharSequence label, Drawable icon) { 149 this.component = component; 150 displayIcon = icon; 151 displayLabel = label; 152 } 153 } 154 155 final class ListAdapter extends BaseAdapter { 156 private final LayoutInflater mInflater; 157 private List<DisplayAppInfo> mList; 158 159 public ListAdapter(Context context, ArrayList<ComponentName> components) { 160 mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 161 // For each component, get the corresponding app name and icon 162 PackageManager pm = getPackageManager(); 163 mList = new ArrayList<DisplayAppInfo>(); 164 165 for (ComponentName component : components) { 166 try { 167 ApplicationInfo appInfo = pm.getApplicationInfo(component.getPackageName(), 0); 168 CharSequence label = appInfo.loadLabel(pm); 169 Drawable icon = appInfo.loadIcon(pm); 170 DisplayAppInfo info = new DisplayAppInfo(component, label, icon); 171 mList.add(info); 172 } catch (NameNotFoundException e) { 173 Log.e(TAG, "Could not load ApplicationInfo for " + component); 174 } 175 } 176 } 177 178 @Override 179 public int getCount() { 180 return mList.size(); 181 } 182 183 @Override 184 public Object getItem(int position) { 185 return mList.get(position); 186 } 187 188 @Override 189 public long getItemId(int position) { 190 return position; 191 } 192 193 @Override 194 public View getView(int position, View convertView, ViewGroup parent) { 195 View view; 196 if (convertView == null) { 197 view = mInflater.inflate( 198 com.android.nfc.R.layout.cardemu_item, parent, false); 199 final ViewHolder holder = new ViewHolder(view); 200 view.setTag(holder); 201 202 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams(); 203 lp.width = lp.height = mIconSize; 204 } else { 205 view = convertView; 206 } 207 208 final ViewHolder holder = (ViewHolder) view.getTag(); 209 DisplayAppInfo appInfo = mList.get(position); 210 holder.text.setText(appInfo.displayLabel); 211 holder.icon.setImageDrawable(appInfo.displayIcon); 212 return view; 213 } 214 } 215 216 static class ViewHolder { 217 public TextView text; 218 public ImageView icon; 219 220 public ViewHolder(View view) { 221 text = (TextView) view.findViewById(com.android.nfc.R.id.applabel); 222 icon = (ImageView) view.findViewById(com.android.nfc.R.id.appicon); 223 } 224 } 225}