Entradas e sensores

O SDK do Android dá acesso às várias entradas e sensores disponíveis com o Glass EE2. Nesta página, você encontra uma visão geral dos recursos disponíveis, detalhes da implementação e dicas úteis.

Gestos de toque

É possível usar o SDK do Android para ativar o acesso a dados brutos do touchpad do Glass. Isso é realizado por um detector de gestos que detecta automaticamente gestos comuns no Glass, como toque, deslize e rolagem.

Você também pode usar esse detector de gestos nos seus apps para considerar toques, deslizar para frente, para trás e para baixo. Isso é semelhante aos dispositivos Glass anteriores.

É melhor usar esses gestos das seguintes maneiras:

  • Toque: confirme ou insira.
  • Deslizar para frente, deslizar para trás: navegue pelos cards e telas.
  • Deslizar para baixo: voltar ou sair.

Para detalhes de implementação, leia o detector de gestos de exemplo.

Detectar gestos com o detector de gestos do Android

O GestureDetector do Android permite detectar gestos simples e complexos, como aqueles que usam vários dedos ou rolagem.

Detectar gestos no nível da atividade

Detecte gestos no nível da atividade apenas quando não importa qual parte da interface tem foco. Por exemplo, se você quiser abrir um menu quando um usuário tocar no touchpad, independente de qual visualização está em foco, processe o MotionEvent na atividade.

Confira abaixo um exemplo de detecção de gestos no nível da atividade que usa GestureDetector e implementa GestureDetector.OnGestureListener para processar gestos reconhecidos, que são processados e traduzidos para o seguinte:

  • TAP
  • SWIPE_FORWARD
  • SWIPE_BACKWARD
  • SWIPE_UP
  • SWIPE_DOWN

Kotlin

class GlassGestureDetector(context: Context, private val onGestureListener: OnGestureListener) :
    GestureDetector.OnGestureListener {

    private val gestureDetector = GestureDetector(context, this)

    enum class Gesture {
        TAP,
        SWIPE_FORWARD,
        SWIPE_BACKWARD,
        SWIPE_UP,
        SWIPE_DOWN
    }

    interface OnGestureListener {
        fun onGesture(gesture: Gesture): Boolean
    }

    fun onTouchEvent(motionEvent: MotionEvent): Boolean {
        return gestureDetector.onTouchEvent(motionEvent)
    }

    override fun onDown(e: MotionEvent): Boolean {
        return false
    }

    override fun onShowPress(e: MotionEvent) {}

    override fun onSingleTapUp(e: MotionEvent): Boolean {
        return onGestureListener.onGesture(Gesture.TAP)
    }

    override fun onScroll(
        e1: MotionEvent,
        e2: MotionEvent,
        distanceX: Float,
        distanceY: Float
    ): Boolean {
        return false
    }

    override fun onLongPress(e: MotionEvent) {}

    /**
     * Swipe detection depends on the:
     * - movement tan value,
     * - movement distance,
     * - movement velocity.
     *
     * To prevent unintentional SWIPE_DOWN and SWIPE_UP gestures, they are detected if movement
     * angle is only between 60 and 120 degrees.
     * Any other detected swipes, will be considered as SWIPE_FORWARD and SWIPE_BACKWARD, depends
     * on deltaX value sign.
     *
     * ______________________________________________________________
     * |                     \        UP         /                    |
     * |                       \               /                      |
     * |                         60         120                       |
     * |                           \       /                          |
     * |                             \   /                            |
     * |  BACKWARD  <-------  0  ------------  180  ------>  FORWARD  |
     * |                             /   \                            |
     * |                           /       \                          |
     * |                         60         120                       |
     * |                       /               \                      |
     * |                     /       DOWN        \                    |
     * --------------------------------------------------------------
     */
    override fun onFling(
        e1: MotionEvent,
        e2: MotionEvent,
        velocityX: Float,
        velocityY: Float
    ): Boolean {
        val deltaX = e2.x - e1.x
        val deltaY = e2.y - e1.y
        val tan =
            if (deltaX != 0f) abs(deltaY / deltaX).toDouble() else java.lang.Double.MAX_VALUE

        return if (tan > TAN_60_DEGREES) {
            if (abs(deltaY) < SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(velocityY) < SWIPE_VELOCITY_THRESHOLD_PX) {
                false
            } else if (deltaY < 0) {
                onGestureListener.onGesture(Gesture.SWIPE_UP)
            } else {
                onGestureListener.onGesture(Gesture.SWIPE_DOWN)
            }
        } else {
            if (Math.abs(deltaX) < SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(velocityX) < SWIPE_VELOCITY_THRESHOLD_PX) {
                false
            } else if (deltaX < 0) {
                onGestureListener.onGesture(Gesture.SWIPE_FORWARD)
            } else {
                onGestureListener.onGesture(Gesture.SWIPE_BACKWARD)
            }
        }
    }

    companion object {

        private const val SWIPE_DISTANCE_THRESHOLD_PX = 100
        private const val SWIPE_VELOCITY_THRESHOLD_PX = 100
        private val TAN_60_DEGREES = tan(Math.toRadians(60.0))
    }
}

Java

  public class GlassGestureDetector implements GestureDetector.OnGestureListener {

   enum Gesture {
     TAP,
     SWIPE_FORWARD,
     SWIPE_BACKWARD,
     SWIPE_UP,
     SWIPE_DOWN,
   }

   interface OnGestureListener {
     boolean onGesture(Gesture gesture);
   }

   private static final int SWIPE_DISTANCE_THRESHOLD_PX = 100;
   private static final int SWIPE_VELOCITY_THRESHOLD_PX = 100;
   private static final double TAN_60_DEGREES = Math.tan(Math.toRadians(60));

   private GestureDetector gestureDetector;
   private OnGestureListener onGestureListener;

   public GlassGestureDetector(Context context, OnGestureListener onGestureListener) {
     gestureDetector = new GestureDetector(context, this);
     this.onGestureListener = onGestureListener;
   }

   public boolean onTouchEvent(MotionEvent motionEvent) {
     return gestureDetector.onTouchEvent(motionEvent);
   }

   @Override
   public boolean onDown(MotionEvent e) {
     return false;
   }

   @Override
   public void onShowPress(MotionEvent e) {
   }

   @Override
   public boolean onSingleTapUp(MotionEvent e) {
     return onGestureListener.onGesture(Gesture.TAP);
   }

   @Override
   public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
     return false;
   }

   @Override
   public void onLongPress(MotionEvent e) {
   }

   /**
    * Swipe detection depends on the:
    * - movement tan value,
    * - movement distance,
    * - movement velocity.
    *
    * To prevent unintentional SWIPE_DOWN and SWIPE_UP gestures, they are detected if movement
    * angle is only between 60 and 120 degrees.
    * Any other detected swipes, will be considered as SWIPE_FORWARD and SWIPE_BACKWARD, depends
    * on deltaX value sign.
    *
    *           ______________________________________________________________
    *          |                     \        UP         /                    |
    *          |                       \               /                      |
    *          |                         60         120                       |
    *          |                           \       /                          |
    *          |                             \   /                            |
    *          |  BACKWARD  <-------  0  ------------  180  ------>  FORWARD  |
    *          |                             /   \                            |
    *          |                           /       \                          |
    *          |                         60         120                       |
    *          |                       /               \                      |
    *          |                     /       DOWN        \                    |
    *           --------------------------------------------------------------
    */
   @Override
   public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
     final float deltaX = e2.getX() - e1.getX();
     final float deltaY = e2.getY() - e1.getY();
     final double tan = deltaX != 0 ? Math.abs(deltaY/deltaX) : Double.MAX_VALUE;

     if (tan > TAN_60_DEGREES) {
       if (Math.abs(deltaY) < SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(velocityY) < SWIPE_VELOCITY_THRESHOLD_PX) {
         return false;
       } else if (deltaY < 0) {
         return onGestureListener.onGesture(Gesture.SWIPE_UP);
       } else {
         return onGestureListener.onGesture(Gesture.SWIPE_DOWN);
       }
     } else {
       if (Math.abs(deltaX) < SWIPE_DISTANCE_THRESHOLD_PX || Math.abs(velocityX) < SWIPE_VELOCITY_THRESHOLD_PX) {
         return false;
       } else if (deltaX < 0) {
         return onGestureListener.onGesture(Gesture.SWIPE_FORWARD);
       } else {
         return onGestureListener.onGesture(Gesture.SWIPE_BACKWARD);
       }
     }
   }
  }

Exemplo de uso

Para usar a detecção de gestos no nível da atividade, conclua as seguintes tarefas:

  1. Adicione a seguinte declaração ao arquivo de manifesto, dentro da declaração do aplicativo. Isso permite que o app receba o MotionEvent na atividade:
    <application>
    <!-- Copy below declaration into your manifest file -->
    <meta-data
      android:name="com.google.android.glass.TouchEnabledApplication"
      android:value="true" />
    </application>
  2. Substitua o método dispatchTouchEvent(motionEvent) da atividade para transmitir os eventos de movimento ao método onTouchEvent(motionEvent) do detector de gestos.
  3. Implemente GlassGestureDetector.OnGestureListener na sua atividade.

Confira um exemplo de detector de gestos no nível da atividade:

Kotlin

class MainAcvitiy : AppCompatActivity(), GlassGestureDetector.OnGestureListener {

    private lateinit var glassGestureDetector: GlassGestureDetector

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        glassGestureDetector = GlassGestureDetector(this, this)
    }

    override fun onGesture(gesture: GlassGestureDetector.Gesture): Boolean {
        when (gesture) {
            TAP ->
                // Response for TAP gesture
                return true
            SWIPE_FORWARD ->
                // Response for SWIPE_FORWARD gesture
                return true
            SWIPE_BACKWARD ->
                // Response for SWIPE_BACKWARD gesture
                return true
            else -> return false
        }
    }

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        return if (glassGestureDetector.onTouchEvent(ev)) {
            true
        } else super.dispatchTouchEvent(ev)
    }
}

Java

  public class MainActivity extends AppCompatActivity implements OnGestureListener {

   private GlassGestureDetector glassGestureDetector;

   @Override
   protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.activity_main);

     glassGestureDetector = new GlassGestureDetector(this, this);
   }

   @Override
   public boolean onGesture(Gesture gesture) {
     switch (gesture) {
       case TAP:
         // Response for TAP gesture
         return true;
       case SWIPE_FORWARD:
         // Response for SWIPE_FORWARD gesture
         return true;
       case SWIPE_BACKWARD:
         // Response for SWIPE_BACKWARD gesture
         return true;
       default:
         return false;
     }
   }

   @Override
   public boolean dispatchTouchEvent(MotionEvent ev) {
     if (glassGestureDetector.onTouchEvent(ev)) {
       return true;
     }
     return super.dispatchTouchEvent(ev);
   }
  }

Entrada de áudio

O Glass Enterprise Edition 2 é um dispositivo padrão baseado no AOSP que oferece suporte a fontes de áudio básicas.

As seguintes fontes de áudio têm processamento de sinal avançado implementado:

Reconhecimento de voz

O Glass Enterprise Edition 2 oferece suporte a uma implementação nativa para reconhecimento de fala. Esse recurso está disponível apenas em inglês.

Imagem do reconhecimento de voz do Glass.

A interface do reconhecimento de fala aguarda o usuário falar e retorna o texto transcrito depois que ele termina. Para iniciar a atividade, siga estas etapas:

  1. Chame startActivityForResult() com a intent ACTION_RECOGNIZE_SPEECH. Os seguintes extras de intent são compatíveis ao iniciar a atividade:
  2. Substitua o callback onActivityResult() para receber o texto transcrito do extra de intent EXTRA_RESULTS conforme mostrado no exemplo de código a seguir. Esse callback é chamado quando o usuário termina de falar.

Kotlin

private const val SPEECH_REQUEST = 109

private fun displaySpeechRecognizer() {
    val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
    startActivityForResult(intent, SPEECH_REQUEST)
}

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
    if (requestCode == SPEECH_REQUEST && resultCode == RESULT_OK) {
        val results: List<String>? =
            data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
        val spokenText = results?.get(0)
        // Do something with spokenText.
    }
    super.onActivityResult(requestCode, resultCode, data)
}

Java

private static final int SPEECH_REQUEST = 109;

private void displaySpeechRecognizer() {
    Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
    startActivityForResult(intent, SPEECH_REQUEST);
}

@Override
protected void onActivityResult(int requestCode, int resultCode,
        Intent data) {
    if (requestCode == SPEECH_REQUEST && resultCode == RESULT_OK) {
        List<String> results = data.getStringArrayListExtra(
                RecognizerIntent.EXTRA_RESULTS);
        String spokenText = results.get(0);
        // Do something with spokenText.
    }
    super.onActivityResult(requestCode, resultCode, data);
}

Para detalhes da implementação, leia o app de exemplo de reconhecimento de voz.

Tendência para palavras-chave

O reconhecimento de fala no Glass pode ser tendencioso para uma lista de palavras-chave. O ajuste aumenta a precisão do reconhecimento de palavras-chave. Para ativar a tendência para palavras-chave, use o seguinte:

Kotlin

val keywords = arrayOf("Example", "Biasing", "Keywords")

val intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
intent.putExtra("recognition-phrases", keywords)

startActivityForResult(intent, SPEECH_REQUEST)

Java

final String[] keywords = {"Example", "Biasing", "Keywords"};

Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra("recognition-phrases", keywords);

startActivityForResult(intent, SPEECH_REQUEST);

Comandos de voz

Com os comandos de voz, os usuários podem realizar ações em atividades. Você cria comandos de voz com as APIs de menu padrão do Android, mas os usuários podem invocar os itens de menu com comandos de voz em vez de toque.

Para ativar os comandos de voz em uma atividade específica, siga estas etapas:

  1. Chame getWindow().requestFeature(FEATURE_VOICE_COMMANDS) na atividade desejada para ativar os comandos de voz. Com esse recurso ativado, o ícone do microfone aparece no canto inferior esquerdo da tela sempre que essa atividade recebe foco.
  2. Solicite a permissão RECORD_AUDIO no app.
  3. Substitua onCreatePanelMenu() e infle um recurso de menu.
  4. Substitua onContextItemSelected() para processar os comandos de voz detectados.

Kotlin

class VoiceCommandsActivity : AppCompatActivity() {

    companion object {
        const val FEATURE_VOICE_COMMANDS = 14
        const val REQUEST_PERMISSION_CODE = 200
        val PERMISSIONS = arrayOf(Manifest.permission.RECORD_AUDIO)
        val TAG = VoiceCommandsActivity::class.java.simpleName
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.requestFeature(FEATURE_VOICE_COMMANDS)
        setContentView(R.layout.activity_voice_commands)

        // Requesting permissions to enable voice commands menu
        ActivityCompat.requestPermissions(
            this,
            PERMISSIONS,
            REQUEST_PERMISSION_CODE
        )
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if (requestCode == REQUEST_PERMISSION_CODE) {
            for (result in grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    Log.d(TAG, "Permission denied. Voice commands menu is disabled.")
                }
            }
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        }
    }

    override fun onCreatePanelMenu(featureId: Int, menu: Menu): Boolean {
        menuInflater.inflate(R.menu.voice_commands_menu, menu)
        return true
    }

    override fun onContextItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            // Handle selected menu item
            R.id.edit -> {
                // Handle edit action
                true
            }
            else -> super.onContextItemSelected(item)
        }
    }
}

Java

public class VoiceCommandsActivity extends AppCompatActivity {

  private static final String TAG = VoiceCommandsActivity.class.getSimpleName();
  private static final int FEATURE_VOICE_COMMANDS = 14;
  private static final int REQUEST_PERMISSION_CODE = 200;
  private static final String[] PERMISSIONS = new String[]{Manifest.permission.RECORD_AUDIO};

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().requestFeature(FEATURE_VOICE_COMMANDS);
    setContentView(R.layout.activity_voice_commands);

    // Requesting permissions to enable voice commands menu
    ActivityCompat.requestPermissions(this, PERMISSIONS, REQUEST_PERMISSION_CODE);
  }

  @Override
  public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (requestCode == REQUEST_PERMISSION_CODE) {
      for (int result : grantResults) {
        if (result != PackageManager.PERMISSION_GRANTED) {
          Log.d(TAG, "Permission denied. Voice commands menu is disabled.");
        }
      }
    } else {
      super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }
  }

  @Override
  public boolean onCreatePanelMenu(int featureId, @NonNull Menu menu) {
    getMenuInflater().inflate(R.menu.voice_commands_menu, menu);
    return true;
  }

  @Override
  public boolean onContextItemSelected(@NonNull MenuItem item) {
    switch (item.getItemId()) {
      // Handle selected menu item
      case R.id.edit:
        // Handle edit action
        return true;
      default:
        return super.onContextItemSelected(item);
    }
  }
}

Confira a seguir um exemplo do recurso de menu usado pela atividade anterior:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/delete"
        android:icon="@drawable/ic_delete"
        android:title="@string/delete"/>
    <item
        android:id="@+id/edit"
        android:icon="@drawable/ic_edit"
        android:title="@string/edit"/>
    <item
        android:id="@+id/find"
        android:icon="@drawable/ic_search"
        android:title="@string/find"/>
</menu>

Leia o app de exemplo para anotações e confira um exemplo completo.

A lista de comandos de voz está sendo recarregada

É possível recarregar dinamicamente a lista de comandos de voz. Para fazer isso, substitua o recurso menu no método onCreatePanelMenu() ou modifique o objeto de menu no método onPreparePanel(). Para aplicar as mudanças, chame o método invalidateOptionsMenu().

Kotlin

private val options = mutableListOf<String>()

fun onPreparePanel(featureId: Int, view: View?, menu: Menu): Boolean {
  if (featureId != FEATURE_VOICE_COMMANDS) {
    return super.onCreatePanelMenu(featureId, menu)
  }
  for (optionTitle in options) {
    menu.add(optionTitle)
  }
  return true
}

/**
 * Method showing example implementation of voice command list modification
 *
 * If you call [Activity.invalidateOptionsMenu] method, voice command  list will be
 * reloaded (onCreatePanelMenu and onPreparePanel methods will be called).
 */
private fun modifyVoiceCommandList() {
  options.add("Delete")
  options.add("Play")
  options.add("Pause")
  invalidateOptionsMenu()
}

Java

private final List<String> options = new ArrayList<>();

@Override
public boolean onPreparePanel(int featureId, View view, Menu menu) {
  if (featureId != FEATURE_VOICE_COMMANDS) {
    return super.onCreatePanelMenu(featureId, menu);
  }
  for (String optionTitle : options) {
    menu.add(optionTitle);
  }
  return true;
}

/**
 * Method showing example implementation of voice command list modification
 *
 * If you call {@link Activity#invalidateOptionsMenu()} method, voice command  list will be
 * reloaded (onCreatePanelMenu and onPreparePanel methods will be called).
 */
private void modifyVoiceCommandList() {
  options.add("Delete");
  options.add("Play");
  options.add("Pause");
  invalidateOptionsMenu();
}

Solução AppCompatActivity

Para recarregar uma lista de comandos de voz em uma atividade que estende AppCompatActivity, use o método sendBroadcast() com a ação de intent reload-voice-commands:

Kotlin

sendBroadcast(Intent("reload-voice-commands"))

Java

sendBroadcast(new Intent("reload-voice-commands"));

Ativar e desativar comandos de voz durante a execução

É possível ativar e desativar os comandos de voz durante a execução. Para fazer isso, retorne um valor adequado do método onCreatePanelMenu() da seguinte maneira:

  • Defina o valor como true para ativar.
  • Defina o valor como false para desativar.

Modo de depuração

Para ativar o modo de depuração para comandos de voz, chame getWindow().requestFeature(FEATURE_DEBUG_VOICE_COMMANDS) na atividade desejada. O modo de depuração ativa os seguintes recursos:

  • O Logcat contém o registro com a frase reconhecida para depuração.
  • A sobreposição da interface é mostrada quando um comando não reconhecido é detectado, como mostrado abaixo:
  • Imagem de comando não reconhecido do reconhecimento de voz do Glass.

Kotlin

class VoiceCommandsActivity : AppCompatActivity() {

    companion object {
        const val FEATURE_VOICE_COMMANDS = 14
        const val FEATURE_DEBUG_VOICE_COMMANDS = 15
        const val REQUEST_PERMISSION_CODE = 200
        val PERMISSIONS = arrayOf(Manifest.permission.RECORD_AUDIO)
        val TAG = VoiceCommandsActivity::class.java.simpleName
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.requestFeature(FEATURE_VOICE_COMMANDS)
        window.requestFeature(FEATURE_DEBUG_VOICE_COMMANDS)
        setContentView(R.layout.activity_voice_commands)

        // Requesting permissions to enable voice commands menu
        ActivityCompat.requestPermissions(
            this,
            PERMISSIONS,
            REQUEST_PERMISSION_CODE
        )
    }
    .
    .
    .
}

Java

public class VoiceCommandsActivity extends AppCompatActivity {

  private static final String TAG = VoiceCommandsActivity.class.getSimpleName();
  private static final int FEATURE_VOICE_COMMANDS = 14;
  private static final int FEATURE_DEBUG_VOICE_COMMANDS = 15;
  private static final int REQUEST_PERMISSION_CODE = 200;
  private static final String[] PERMISSIONS = new String[]{Manifest.permission.RECORD_AUDIO};

  @Override
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().requestFeature(FEATURE_VOICE_COMMANDS);
    getWindow().requestFeature(FEATURE_DEBUG_VOICE_COMMANDS);
    setContentView(R.layout.activity_voice_commands);

    // Requesting permissions to enable voice commands menu
    ActivityCompat.requestPermissions(this, PERMISSIONS, REQUEST_PERMISSION_CODE);
  }
  .
  .
  .
}

Para detalhes da implementação, leia o app de recarregamento de comandos de voz de exemplo.

Conversão de texto em voz (TTS)

A funcionalidade Text-to-Speech converte texto digital em saída de fala sintetizada. Para mais informações, acesse Documentação do Android Developers TextToSpeech.

O Glass EE2 tem o mecanismo de conversão de texto em voz do Google instalado. Ele é definido como o mecanismo de TTS padrão e funciona off-line.

As seguintes localidades estão incluídas no mecanismo de conversão de texto em voz do Google:

Bengali
Chinês (mandarim)
Tcheco
Dinamarquês
Alemão
Grego
Inglês
Espanhol
Estoniano
Finlandês
Francês
Guzerate
Hindi
Húngaro
Indonésio
Italiano
Japonês
Javanês
Austronésio
Austro-asiático
Canará
Coreano
Malaiala
Norueguês
Holandês
Polonês
Português
Russo
Eslovaco
Sundanês
Sueco
Tâmil
Telugu
Tailandês
Turco
Ucraniano
Vietnamita

Câmera

O Glass Enterprise Edition 2 está equipado com uma câmera de 8 megapixels e foco fixo com abertura de f/2,4, proporção de sensor de 4:3 e campo de visão diagonal de 83° (71° x 57° na orientação paisagem). Recomendamos usar a API padrão CameraX ou Camera2.

Para detalhes da implementação, leia o app de câmera de exemplo.

Botão "Câmera"

O botão da câmera é o botão físico na dobradiça do dispositivo Glass Enterprise Edition 2. Ele pode ser processado como uma ação de teclado padrão e identificado pelo código de tecla KeyEvent#KEYCODE_CAMERA.

A partir da atualização do SO OPM1.200313.001, as intents com as seguintes ações são enviadas do app Launcher:

Sensores

Há vários sensores disponíveis para os desenvolvedores criarem aplicativos no Glass EE2.

Os seguintes sensores padrão do Android são compatíveis com o Glass:

Os seguintes sensores do Android não são compatíveis com o Glass:

O sistema de coordenadas do sensor do Glass é mostrado na ilustração a seguir. Ele é relativo à tela do Glass. Para mais informações, consulte Sistema de coordenadas do sensor.

O sistema de coordenadas do sensor do Glass é mostrado aqui em relação à tela do Glass.

O acelerômetro, o giroscópio e o magnetômetro estão localizados no módulo óptico do dispositivo Glass, que os usuários giram para alinhar o dispositivo à visão. Não é possível medir o ângulo do módulo óptico diretamente. Portanto, tenha isso em mente ao usar ângulos desses sensores para aplicativos, como uma direção de bússola.

Para preservar a bateria, ouça os sensores apenas quando necessário. Considere as necessidades e o ciclo de vida do app ao decidir quando começar e parar de usar os sensores.

Os callbacks de eventos do sensor são executados na linha de execução da interface. Portanto, processe eventos e retornos o mais rápido possível. Se o processamento demorar muito, envie os eventos do sensor para uma fila e use uma linha de execução em segundo plano para processá-los.

50 Hz geralmente é uma taxa de amostragem suficiente para rastrear o movimento da cabeça.

Para mais informações sobre como usar sensores, consulte o guia para desenvolvedores Android.

Serviços de Localização

O dispositivo Glass Enterprise Edition 2 não está equipado com um módulo GPS e não informa a localização do usuário. No entanto, ele tem serviços de localização implementados, o que é necessário para mostrar uma lista de redes Wi-Fi e dispositivos Bluetooth por perto.

Se o aplicativo tiver privilégios de proprietário do dispositivo, use-o para mudar de forma programática o valor da configuração segura correspondente:

Kotlin

val devicePolicyManager = context
    .getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager
if (devicePolicyManager.isDeviceOwnerApp(context.getPackageName())) {
    val componentName = ComponentName(context, MyDeviceAdmin::class.java)
    devicePolicyManager.setSecureSetting(
        componentName,
        Settings.Secure.LOCATION_MODE,
        Settings.Secure.LOCATION_MODE_SENSORS_ONLY.toString()
    )
}

Java

final DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context
    .getSystemService(Context.DEVICE_POLICY_SERVICE);
if (devicePolicyManager.isDeviceOwnerApp(context.getPackageName())) {
  final ComponentName componentName = new ComponentName(context, MyDeviceAdmin.class);
  devicePolicyManager.setSecureSetting(componentName, Settings.Secure.LOCATION_MODE,
      String.valueOf(Settings.Secure.LOCATION_MODE_SENSORS_ONLY));
}

Se você usa uma solução de MDM de terceiros, ela precisa conseguir mudar essas configurações para você.