Home | History | Annotate | Download | only in cardemulation
      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
     75     protected void onDestroy() {
     76         super.onDestroy();
     77         unregisterReceiver(mReceiver);
     78     }
     79 
     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
    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
    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 
    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 
    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
    222         public int getCount() {
    223             return mList.size();
    224         }
    225 
    226         @Override
    227         public Object getItem(int position) {
    228             return mList.get(position);
    229         }
    230 
    231         @Override
    232         public long getItemId(int position) {
    233             return position;
    234         }
    235 
    236         @Override
    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;
    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 }