inPocket
A framework de desenvolvimento de aplicações Android está definida em linguagem de programação Java, o que facilita e aligeira bastante a tarefa de implementação da aplicação, visto que existem muitas opções na biblioteca da máquina virtual, para implementar fios de execução e protecções de sincronização.
28
5.2.1 Algoritmo utilizado para tratar os dados do sensor de
proximidade
O sensor de proximidade é utilizado para detectar se o dispositivo está ou não no bolso do utilizador.
A ideia base seria, periodicamente, verificar o valor que este retorna (normalmente tem apenas um conjunto de dois valores possíveis: perto ou longe), e se o retorno fosse perto, considerava-se que o dispositivo estava dentro do bolso. Caso contrario considerar-se-ia que o dispositivo estaria fora do bolso.
Na verdade o que a framework permite é implementar a interface SensorEventListener [28], e registar a implementação como receptora dos eventos do sensor pretendido, através do método onSensorChanged(Sensor sensor, int accuracy).
A opção tomada foi lançar uma Thread Java [29], por cada valor recebido do sensor de proximidade e proteger o método de detecção com o Lock [30] comum a todas as
Threads. Abaixo temos o algoritmo desta detecção (no valor de retorno do sensor,
admitimos que o valor booleano verdadeiro significa perto):
detect (boolean value):
inOutLock.lock() if(status.isTransitioning() and value=status.hasProximitySensorChanged()): status.cancelProximityTimer() status.setNotTransitioning() else: toggleNearFar(value) inOutLock.unLock() toggleNearFar(boolean value): status.setTransitioning() if(status.isProximityTimerRunnging()): status.cancelProximityTimer() var newTimerTask:=newTimerTask{ run(): inOutLock.lock() status.setNotTransitioning() status.setProximitySensorChanged(value) if(value): status.setNear() else: status.setFar() status.nullProximityTimer() inOutLock.unlock() checkinOutPocket() } status.scheduleNewProximityTask(newProximityTask, TRANSISITON_TIME)
À primeira vista estes artifícios podem parecer demasiado complicados para uma simples detecção de um obstáculo à frente do sensor de proximidade, mas na verdade o que se pretende aqui fazer é mais que isso.
29
O sensor de proximidade é reactivo, tanto a um bolso, como a uma mão que inadvertidamente o utilizador lhe põe à frente e, como tal, não queremos que o sistema “se deixe enganar” tão facilmente. É aqui que entra o conceito de transição.
Sempre que o valor do sensor for actualizado é chamada a rotina detect, e esta verifica se o sistema está em transição.
Se estiver em transição e o valor actual for diferente do último e perto, ou então, igual ao último e longe, conclui-se que o caso é um “falso alarme” e a transição pode ser descartada.
Caso contrario dá-se início a uma nova transição, o que implica, com um atraso t, lançar uma nova tarefa paralela, que anula alguma eventual tarefa anterior do mesmo tipo, e define como valor de proximidade o valor recebido pela tarefa que a lançou.
O atraso t é o valor de afinação deste algoritmo, já que representa o tempo de transição em que a aplicação precisará de estar constantemente a detectar um objecto perto do dispositivo, sem interrupções, para que o considere “dentro do bolso”.
A rotina checkInOutPocket() verifica o valor definido em setNear() ou setFar() para decidir se considera que o dispositivo está dentro ou fora do bolso.
5.2.2 Algoritmo utilizado para definir um volume de toque
compatível com o nível de ruído
O principal objectivo do modo outPocket é fazer com que o dispositivo toque baixo se o ruído do meio ambiente for baixo e que tente ser audível no caso de se encontrar num meio ruidoso.
Em seguida mostra-se o algoritmo utilizado para fazer este ajuste de volume:
adjustVolume(recorder : AudioRecorder) : int
var buffer := new short[BUFFER_SIZE] recorder.startRecording(buffer) var amp := listen(recorder,buffer)
return maximum(amp*MAX_RING_VOLUME/MAX_SHORT_VALUE,1)
listen (recorder : AudioRecorder, buffer : short[]) : short
var min:=0 var max:=0
for (var i:=0 , i < buffer.length , i++) var val:=buffer[i] if(max=0 or val>max) Max:=val if(min=0 or val<min) min:=val return absoluteValue(max-min)
Este algoritmo, estruturalmente menos elaborado, é executado apenas quando é preciso ajustar o volume de toque. Assim, há que ter cuidado com a sua complexidade.
30
Quando é recebida uma chamada/mensagem escrita e o dispositivo vai tocar, o volume de toque é posto a zero, momentaneamente, para que o mesmo possa ser ajustado sem interferências. Se este processo for demasiado lento, o que acontece é que a chamada pode terminar entretanto.
Explicando um pouco melhor o algoritmo, o que se faz aqui é obter uma amostra do som ambiente, gravando para um buffer de tamanho BUFFER_SIZE, o qual é depois percorrido com o objectivo de achar o seu máximo e o seu mínimo.
O valor absoluto (abs) da subtracção destes dois valores é a amplitude máxima registada na amostra de som obtida. O valor máximo de amplitude registável pelo dispositivo é o valor máximo do tipo de dados short.
Depois basta aplicar uma regra de três simples (a amplitude máxima está para o volume máximo de toque assim como a amplitude máxima medida está para o volume a definir), de forma a relacionar estes dois valores, e daí obter um valor de volume de toque.
O tempo de gravação é dado pelo tamanho do buffer de gravação sendo que os pormenores de inicialização do objecto AudioRecord [31] não são aqui descritos.
5.2.3 Uma nova funcionalidade decidida no momento de
implementação
No final da implementação da aplicação Droid inPocket, no momento da transição para a fase de testes, percebeu-se que o sensor de proximidade funciona de formas diferentes em dispositivos diferentes.
Em alguns dispositivos, este sensor apenas detecta superfícies de determinados materiais, têxteis, por exemplo, não detectando superfícies demasiado lisas, como plástico ou vidro.
Já noutros dispositivos, o sensor de proximidade detecta qualquer superfície, incluindo vidro não pintado, pelo que, nestes casos se dispensa o uso do acelerómetro para verificar se o dispositivo tem o ecrã voltado para baixo.
Assim, e porque o sensor de aceleração, tendo uma precisão elevada, tem uma taxa de actualização elevada também, percebeu-se que nos casos em que não é imprescindível, é um gasto desnecessário e não desprezível em termos de tempo de processador utilizado pela aplicação e, consequentemente, de bateria.
Concluiu-se então que seria benéfico para os utilizadores dispor de uma opção em que podem desactivar a utilização deste sensor, uma vez que a funcionalidade a que se destina está garantida pelo sensor de proximidade, nos casos descritos no parágrafo anterior.
31
Daqui nasceu a funcionalidade “Use accelerometer sensor”, comum a ambas as versões e acessível através do ecrã do modo inPocket.