• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.nfc.cardemulation;
18 
19 import com.android.internal.R;
20 import com.android.internal.app.AlertActivity;
21 import com.android.internal.app.AlertController;
22 
23 import java.util.ArrayList;
24 import java.util.List;
25 
26 import android.app.ActivityManager;
27 import android.content.BroadcastReceiver;
28 import android.content.ComponentName;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.IntentFilter;
32 import android.content.pm.ApplicationInfo;
33 import android.content.pm.PackageManager;
34 import android.content.pm.PackageManager.NameNotFoundException;
35 import android.graphics.drawable.Drawable;
36 import android.nfc.NfcAdapter;
37 import android.nfc.cardemulation.ApduServiceInfo;
38 import android.nfc.cardemulation.CardEmulation;
39 import android.os.Bundle;
40 import android.util.Log;
41 import android.view.LayoutInflater;
42 import android.view.View;
43 import android.view.ViewGroup;
44 import android.view.Window;
45 import android.view.WindowManager;
46 import android.widget.AdapterView;
47 import android.widget.BaseAdapter;
48 import android.widget.ImageView;
49 import android.widget.ListView;
50 import android.widget.TextView;
51 
52 public class AppChooserActivity extends AlertActivity
53         implements AdapterView.OnItemClickListener {
54 
55     static final String TAG = "AppChooserActivity";
56 
57     public static final String EXTRA_APDU_SERVICES = "services";
58     public static final String EXTRA_CATEGORY = "category";
59     public static final String EXTRA_FAILED_COMPONENT = "failed_component";
60 
61     private int mIconSize;
62     private ListView mListView;
63     private ListAdapter mListAdapter;
64     private CardEmulation mCardEmuManager;
65     private String mCategory;
66 
67     final BroadcastReceiver mReceiver = new BroadcastReceiver() {
68         @Override
69         public void onReceive(Context context, Intent intent) {
70             finish();
71         }
72     };
73 
74     @Override
onDestroy()75     protected void onDestroy() {
76         super.onDestroy();
77         unregisterReceiver(mReceiver);
78     }
79 
onCreate(Bundle savedInstanceState, String category, ArrayList<ApduServiceInfo> options, ComponentName failedComponent)80     protected void onCreate(Bundle savedInstanceState, String category,
81             ArrayList<ApduServiceInfo> options, ComponentName failedComponent) {
82         super.onCreate(savedInstanceState);
83         setTheme(R.style.Theme_DeviceDefault_Light_Dialog_Alert);
84 
85         IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
86         registerReceiver(mReceiver, filter);
87 
88         if ((options == null || options.size() == 0) && failedComponent == null) {
89             Log.e(TAG, "No components passed in.");
90             finish();
91             return;
92         }
93 
94 
95         mCategory = category;
96         boolean isPayment = CardEmulation.CATEGORY_PAYMENT.equals(mCategory);
97 
98         final NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);
99         mCardEmuManager = CardEmulation.getInstance(adapter);
100         AlertController.AlertParams ap = mAlertParams;
101 
102         final ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
103         mIconSize = am.getLauncherLargeIconSize();
104 
105         // Three cases:
106         // 1. Failed component and no alternatives: just an OK box
107         // 2. Failed component and alternatives: pick alternative
108         // 3. No failed component and alternatives: pick alternative
109         PackageManager pm = getPackageManager();
110 
111         CharSequence applicationLabel = "unknown";
112         if (failedComponent != null) {
113             try {
114                 ApplicationInfo info = pm.getApplicationInfo(failedComponent.getPackageName(), 0);
115                 applicationLabel = info.loadLabel(pm);
116             } catch (NameNotFoundException e) {
117             }
118 
119         }
120         if (options.size() == 0 && failedComponent != null) {
121             String formatString = getString(com.android.nfc.R.string.transaction_failure);
122             ap.mTitle = "";
123             ap.mMessage = String.format(formatString, applicationLabel);
124             ap.mPositiveButtonText = getString(R.string.ok);
125             setupAlert();
126         } else {
127             mListAdapter = new ListAdapter(this, options);
128             if (failedComponent != null) {
129                 String formatString = getString(com.android.nfc.R.string.could_not_use_app);
130                 ap.mTitle = String.format(formatString, applicationLabel);
131                 ap.mNegativeButtonText = getString(R.string.cancel);
132             } else {
133                 if (CardEmulation.CATEGORY_PAYMENT.equals(category)) {
134                     ap.mTitle = getString(com.android.nfc.R.string.pay_with);
135                 } else {
136                     ap.mTitle = getString(com.android.nfc.R.string.complete_with);
137                 }
138             }
139             ap.mView = getLayoutInflater().inflate(com.android.nfc.R.layout.cardemu_resolver, null);
140 
141             mListView = (ListView) ap.mView.findViewById(com.android.nfc.R.id.resolver_list);
142             if (isPayment) {
143                 mListView.setDivider(getResources().getDrawable(android.R.color.transparent));
144                 int height = (int) (getResources().getDisplayMetrics().density * 16);
145                 mListView.setDividerHeight(height);
146             } else {
147                 mListView.setPadding(0, 0, 0, 0);
148             }
149             mListView.setAdapter(mListAdapter);
150             mListView.setOnItemClickListener(this);
151 
152             setupAlert();
153         }
154         Window window = getWindow();
155         window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
156     }
157 
158     @Override
onCreate(Bundle savedInstanceState)159     protected void onCreate(Bundle savedInstanceState) {
160         Intent intent = getIntent();
161         ArrayList<ApduServiceInfo> services = intent.getParcelableArrayListExtra(EXTRA_APDU_SERVICES);
162         String category = intent.getStringExtra(EXTRA_CATEGORY);
163         ComponentName failedComponent = intent.getParcelableExtra(EXTRA_FAILED_COMPONENT);
164         onCreate(savedInstanceState, category, services, failedComponent);
165     }
166 
167     @Override
onItemClick(AdapterView<?> parent, View view, int position, long id)168     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
169         DisplayAppInfo info = (DisplayAppInfo) mListAdapter.getItem(position);
170         mCardEmuManager.setDefaultForNextTap(info.serviceInfo.getComponent());
171         Intent dialogIntent = new Intent(this, TapAgainDialog.class);
172         dialogIntent.putExtra(TapAgainDialog.EXTRA_CATEGORY, mCategory);
173         dialogIntent.putExtra(TapAgainDialog.EXTRA_APDU_SERVICE, info.serviceInfo);
174         startActivity(dialogIntent);
175         finish();
176     }
177 
178     final class DisplayAppInfo {
179         ApduServiceInfo serviceInfo;
180         CharSequence displayLabel;
181         Drawable displayIcon;
182         Drawable displayBanner;
183 
DisplayAppInfo(ApduServiceInfo serviceInfo, CharSequence label, Drawable icon, Drawable banner)184         public DisplayAppInfo(ApduServiceInfo serviceInfo, CharSequence label, Drawable icon,
185                 Drawable banner) {
186             this.serviceInfo = serviceInfo;
187             displayIcon = icon;
188             displayLabel = label;
189             displayBanner = banner;
190         }
191     }
192 
193     final class ListAdapter extends BaseAdapter {
194         private final LayoutInflater mInflater;
195         private final boolean mIsPayment;
196         private List<DisplayAppInfo> mList;
197 
ListAdapter(Context context, ArrayList<ApduServiceInfo> services)198         public ListAdapter(Context context, ArrayList<ApduServiceInfo> services) {
199             mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
200             // For each component, get the corresponding app name and icon
201             PackageManager pm = getPackageManager();
202             mList = new ArrayList<DisplayAppInfo>();
203             mIsPayment = CardEmulation.CATEGORY_PAYMENT.equals(mCategory);
204             for (ApduServiceInfo service : services) {
205                 CharSequence label = service.getDescription();
206                 if (label == null) label = service.loadLabel(pm);
207                 Drawable icon = service.loadIcon(pm);
208                 Drawable banner = null;
209                 if (mIsPayment) {
210                     banner = service.loadBanner(pm);
211                     if (banner == null) {
212                         Log.e(TAG, "Not showing " + label + " because no banner specified.");
213                         continue;
214                     }
215                 }
216                 DisplayAppInfo info = new DisplayAppInfo(service, label, icon, banner);
217                 mList.add(info);
218             }
219         }
220 
221         @Override
getCount()222         public int getCount() {
223             return mList.size();
224         }
225 
226         @Override
getItem(int position)227         public Object getItem(int position) {
228             return mList.get(position);
229         }
230 
231         @Override
getItemId(int position)232         public long getItemId(int position) {
233             return position;
234         }
235 
236         @Override
getView(int position, View convertView, ViewGroup parent)237         public View getView(int position, View convertView, ViewGroup parent) {
238             View view;
239             if (convertView == null) {
240                 if (mIsPayment) {
241                     view = mInflater.inflate(
242                             com.android.nfc.R.layout.cardemu_payment_item, parent, false);
243                 } else {
244                     view = mInflater.inflate(
245                             com.android.nfc.R.layout.cardemu_item, parent, false);
246                 }
247                 final ViewHolder holder = new ViewHolder(view);
248                 view.setTag(holder);
249 
250             } else {
251                 view = convertView;
252             }
253 
254             final ViewHolder holder = (ViewHolder) view.getTag();
255             DisplayAppInfo appInfo = mList.get(position);
256             if (mIsPayment) {
257                 holder.banner.setImageDrawable(appInfo.displayBanner);
258             } else {
259                 ViewGroup.LayoutParams lp = holder.icon.getLayoutParams();
260                 lp.width = lp.height = mIconSize;
261                 holder.icon.setImageDrawable(appInfo.displayIcon);
262                 holder.text.setText(appInfo.displayLabel);
263             }
264             return view;
265         }
266     }
267 
268     static class ViewHolder {
269         public TextView text;
270         public ImageView icon;
271         public ImageView banner;
ViewHolder(View view)272         public ViewHolder(View view) {
273             text = (TextView) view.findViewById(com.android.nfc.R.id.applabel);
274             icon = (ImageView) view.findViewById(com.android.nfc.R.id.appicon);
275             banner = (ImageView) view.findViewById(com.android.nfc.R.id.banner);
276         }
277     }
278 }