All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.android.se.omapi.SEService Maven / Gradle / Ivy

Go to download

A library jar that provides APIs for Applications written for the Google Android Platform.

There is a newer version: 15-robolectric-12650502
Show newest version
/*
 * Copyright (C) 2017 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.
 */
/*
 * Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
 */
/*
 * Contributed by: Giesecke & Devrient GmbH.
 */

package android.se.omapi;

import android.annotation.BroadcastBehavior;
import android.annotation.NonNull;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import java.util.HashMap;
import java.util.concurrent.Executor;

/**
 * The SEService realises the communication to available Secure Elements on the
 * device. This is the entry point of this API. It is used to connect to the
 * infrastructure and get access to a list of Secure Element Readers.
 *
 * @see SIMalliance Open Mobile API  v3.0
 */
public final class SEService {

    /**
     * Error code used with ServiceSpecificException.
     * Thrown if there was an error communicating with the Secure Element.
     *
     * @hide
     */
    public static final int IO_ERROR = 1;

    /**
     * Error code used with ServiceSpecificException.
     * Thrown if AID cannot be selected or is not available when opening
     * a logical channel.
     *
     * @hide
     */
    public static final int NO_SUCH_ELEMENT_ERROR = 2;

    /**
     * Interface to send call-backs to the application when the service is connected.
     */
    public interface OnConnectedListener {
        /**
         * Called by the framework when the service is connected.
         */
        void onConnected();
    }

    /**
     * Broadcast Action: Intent to notify if the secure element state is changed.
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    @BroadcastBehavior(registeredOnly = true, protectedBroadcast = true)
    public static final String ACTION_SECURE_ELEMENT_STATE_CHANGED =
            "android.se.omapi.action.SECURE_ELEMENT_STATE_CHANGED";

    /**
     * Mandatory extra containing the reader name of the state changed secure element.
     *
     * @see Reader#getName()
     */
    public static final String EXTRA_READER_NAME = "android.se.omapi.extra.READER_NAME";

    /**
     * Mandatory extra containing the connected state of the state changed secure element.
     *
     * True if the secure element is connected correctly, false otherwise.
     */
    public static final String EXTRA_READER_STATE = "android.se.omapi.extra.READER_STATE";

    /**
     * Listener object that allows the notification of the caller if this
     * SEService could be bound to the backend.
     */
    private class SEListener extends ISecureElementListener.Stub {
        public OnConnectedListener mListener = null;
        public Executor mExecutor = null;

        @Override
        public IBinder asBinder() {
            return this;
        }

        public void onConnected() {
            if (mListener != null && mExecutor != null) {
                mExecutor.execute(new Runnable() {
                    @Override
                    public void run() {
                        mListener.onConnected();
                    }
                });
            }
        }
    }
    private SEListener mSEListener = new SEListener();

    private static final String TAG = "OMAPI.SEService";

    private static final String UICC_TERMINAL = "SIM";

    private final Object mLock = new Object();

    /** The client context (e.g. activity). */
    private final Context mContext;

    /** The backend system. */
    private volatile ISecureElementService mSecureElementService;

    /**
     * Class for interacting with the main interface of the backend.
     */
    private ServiceConnection mConnection;

    /**
     * Collection of available readers
     */
    private final HashMap mReaders = new HashMap();

    /**
     * Establishes a new connection that can be used to connect to all the
     * Secure Elements available in the system. The connection process can be
     * quite long, so it happens in an asynchronous way. It is usable only if
     * the specified listener is called or if isConnected() returns
     * true. 
* The call-back object passed as a parameter will have its * onConnected() method called when the connection actually happen. * * @param context * the context of the calling application. Cannot be * null. * @param listener * a OnConnectedListener object. * @param executor * an Executor which will be used when invoking the callback. */ public SEService(@NonNull Context context, @NonNull Executor executor, @NonNull OnConnectedListener listener) { if (context == null || listener == null || executor == null) { throw new NullPointerException("Arguments must not be null"); } mContext = context; mSEListener.mListener = listener; mSEListener.mExecutor = executor; mConnection = new ServiceConnection() { public synchronized void onServiceConnected( ComponentName className, IBinder service) { mSecureElementService = ISecureElementService.Stub.asInterface(service); if (mSEListener != null) { mSEListener.onConnected(); } Log.i(TAG, "Service onServiceConnected"); } public void onServiceDisconnected(ComponentName className) { mSecureElementService = null; Log.i(TAG, "Service onServiceDisconnected"); } }; Intent intent = new Intent(ISecureElementService.class.getName()); intent.setClassName("com.android.se", "com.android.se.SecureElementService"); boolean bindingSuccessful = mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); if (bindingSuccessful) { Log.i(TAG, "bindService successful"); } } /** * Tells whether or not the service is connected. * * @return true if the service is connected. */ public boolean isConnected() { return mSecureElementService != null; } /** * Returns an array of available Secure Element readers. * There must be no duplicated objects in the returned list. * All available readers shall be listed even if no card is inserted. * * @return An array of Readers. If there are no readers the returned array * is of length 0. */ public @NonNull Reader[] getReaders() { loadReaders(); return mReaders.values().toArray(new Reader[0]); } /** * Obtain a UICC Reader instance with specific slot number from the SecureElementService * * @param slotNumber The index of the uicc slot. The index starts from 1. * @throws IllegalArgumentException if the reader object corresponding to the uiccSlotNumber * is not exist. * @return A Reader object for this uicc slot. */ public @NonNull Reader getUiccReader(int slotNumber) { if (slotNumber < 1) { throw new IllegalArgumentException("slotNumber should be larger than 0"); } loadReaders(); String readerName = UICC_TERMINAL + slotNumber; Reader reader = mReaders.get(readerName); if (reader == null) { throw new IllegalArgumentException("Reader:" + readerName + " doesn't exist"); } return reader; } /** * Releases all Secure Elements resources allocated by this SEService * (including any binding to an underlying service). * As a result isConnected() will return false after shutdown() was called. * After this method call, the SEService object is not connected. * This method should be called when connection to the Secure Element is not needed * or in the termination method of the calling application * (or part of this application) which is bound to this SEService. */ public void shutdown() { synchronized (mLock) { if (mSecureElementService != null) { for (Reader reader : mReaders.values()) { try { reader.closeSessions(); } catch (Exception ignore) { } } } try { mContext.unbindService(mConnection); } catch (IllegalArgumentException e) { // Do nothing and fail silently since an error here indicates // that binding never succeeded in the first place. } mSecureElementService = null; } } /** * Returns the version of the OpenMobile API specification this * implementation is based on. * * @return String containing the OpenMobile API version (e.g. "3.0"). */ public @NonNull String getVersion() { return "3.3"; } @NonNull ISecureElementListener getListener() { return mSEListener; } /** * Obtain a Reader instance from the SecureElementService */ private @NonNull ISecureElementReader getReader(String name) { try { return mSecureElementService.getReader(name); } catch (RemoteException e) { throw new IllegalStateException(e.getMessage()); } } /** * Load available Secure Element Readers */ private void loadReaders() { if (mSecureElementService == null) { throw new IllegalStateException("service not connected to system"); } String[] readerNames; try { readerNames = mSecureElementService.getReaders(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } for (String readerName : readerNames) { if (mReaders.get(readerName) == null) { try { mReaders.put(readerName, new Reader(this, readerName, getReader(readerName))); } catch (Exception e) { Log.e(TAG, "Error adding Reader: " + readerName, e); } } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy