Implementação da tela PIN TEF

Ingenico

A Ingenico tem um mecanismo de skin para montar a tela de senha. A integradora terá que implementar conforme o exemplo abaixo:

private void configurePinpadSkin() {
    // Configura layout customizado do PINPAD
    Intent configureSkin = new Intent("com.landicorp.pinpad.pinentry.server.SET_SKIN");
    configureSkin.putExtra("disorder", false);
    // Força texto de entrada (os ‘*’) a ser apresentada
    configureSkin.putExtra("show_input", true);
    // Define o nome da Skin
    configureSkin.putExtra("skin_name", "GETNET4");
    // Totalmente transparente
    configureSkin.putExtra("dim_amount", 0);
    // Tamanho em altura do PinPad
    configureSkin.putExtra("skb_height", 580);
    // Comunica a configuração ao serviço pinentry
    mContext.sendBroadcast(configureSkin);
}
private fun configurePinpadSkin() {
     // Configura layout customizado do PINPAD
    val configureSkin = Intent("com.landicorp.pinpad.pinentry.server.SET_SKIN").apply {
        putExtra("disorder", false)
        // Força texto de entrada (os ‘*’) a ser apresentada
        putExtra("show_input", true)
        // Define o nome da Skin
        putExtra("skin_name", "GETNET4")
        // Totalmente transparente
        putExtra("dim_amount", 0)
        // Tamanho em altura do PinPad
        putExtra("skb_height", 580)
    }
     // Comunica a configuração ao serviço pinentry
    mContext.sendBroadcast(configureSkin)
}
const configurePinpadSkin = () => {
    const extras: { [key: string]: string|int|boolean } = {
      'disorder': false,
       // Força texto de entrada (os ‘*’) a ser apresentada
      'show_input': true,
      // Define o nome da Skin
      'skin_name': 'GETNET4',
      // Totalmente transparente
      'dim_amount': 0,
      // Tamanho em altura do PinPad
      'skb_height': 580
    };

    const intentParams = {
      extra: extras,
    };
    // Comunica a configuração ao serviço pinentry
    IntentLauncher.startActivityAsync('com.landicorp.pinpad.pinentry.server.SET_SKIN', intentParams);
}

Será necessário fazer uso do código nativo:

package com.example.deeplink_test

import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result

import android.app.Activity
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log

class MainActivity: FlutterActivity(), MethodCallHandler {
    private val CHANNEL = "sample.android/deeplink"
    private lateinit var channel: MethodChannel
    private var callback: Result? = null

    private var requestCode: Int = -1

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).apply {
            setMethodCallHandler(this@MainActivity)
        }
    }

    override fun onMethodCall(call: MethodCall, result: Result) {
        var action = ""
        var bundle = Bundle()

        when(call.method) {
            "sendBroadcast" -> {
                callback = result
                val params = call.arguments as? Map<String, Any>
                params?.run {
                    for ((key, value) in this) {
                        when(key.toString()) {
                            "action" -> action = value.toString()
                            "arguments" -> {
                                bundle.apply{
                                    for((argKey, argValue) in (value as Map<String, Any>)) {
                                        when(argValue) {
                                            is String -> putString(argKey, argValue as String)
                                            is Int -> putInt(argKey, argValue as Int)
                                            is Boolean -> putBoolean(argKey, argValue as Boolean)
                                        }
                                    }
                                }
                            }
                        }
                    }
                    val intent = Intent(action).apply {
                        putExtras(bundle)
                    }
                    sendBroadcast(intent)
                    callback?.success(1)
                }
            }
            else -> result.notImplemented()
        }
    }
}

E com o código nativo criado, podemos chamar ele através do sendBroadcast abaixo:

import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key,});

  @override
  State<MyApp> createState() {
    return _MyAppState();
  }
}

class _MyAppState extends State<MyApp> {

  static const platform = MethodChannel('sample.android/deeplink');

  void sendBroadcast(String action, Map<String, dynamic> bundle) async {
      try {
        final intent = {
          'action': action,
          'arguments': bundle,
        };
        var result = await platform.invokeMethod('sendBroadcast', intent);
        if (result == 1) {
          log('sendBroadcast enviado com sucesso!');
        } else {
          log('Error launching intent: $action');
        }
      } catch (e) {
        log('Error launching intent: $e');
      }
  }

  void _sendBroadcast() {
    Map<String, dynamic> intentParams = {
        'disorder': false,
        'show_input': true,
        'skin_name': 'GETNET4',
        'dim_amount': 0,
        'skb_height': 580
    };
    sendBroadcast('com.landicorp.pinpad.pinentry.server.SET_SKIN', intentParams);
  }

  @override
  void initState() {
    super.initState();
    _sendBroadcast();
  }
  @override
  Widget build(BuildContext context) {
    return ();
  }
}

Este mecanismo enviará um broadcast para o service da Ingenico que quando for chamado um goOnChip ou getPin, a tela de senha será invocada pelo service e ficará em primeiro plano.

Atualmente, além da skin default do fabricante existem 3 opções de skin customizadas: GETNET4, SKIN_LIGHT, SKIN_DARK. Para ter acesso a essas skins baixe o aplicativo “Teclados de Senha para TEF” no Portal do Desenvolvedor.

Para usar a skin default do fabricante basta remover a linha:

“configureSkin.putExtra("skin_name", "GETNET4");”. Para as outras você deverá substituir o GETNET4 pelas demais citadas anteriormente.