Входы и датчики

Android SDK предоставляет вам доступ к различным входам и датчикам, доступным в Glass EE2. На этой странице представлен обзор доступных функций, сведения о реализации и полезные советы.

Сенсорные жесты

Вы можете использовать Android SDK, чтобы разрешить доступ к необработанным данным с сенсорной панели Glass. Это достигается с помощью детектора жестов, который автоматически определяет распространенные жесты на Glass, такие как касание, бросок и прокрутка.

Вы также можете использовать этот детектор жестов в своих приложениях для учета касаний, пролистывания вперед, пролистывания назад и пролистывания вниз. Это похоже на предыдущие устройства Glass.

Лучше всего использовать эти жесты следующими способами:

  • Нажмите : Подтвердить или ввести.
  • Проведите вперед , проведите назад : навигация по картам и экранам.
  • Проведите вниз : Назад или выход.

Подробности реализации читайте в примере детектора жестов .

Обнаружение жестов с помощью детектора жестов Android

Android GestureDetector позволяет обнаруживать простые и сложные жесты, например жесты с использованием нескольких пальцев или прокрутки.

Обнаружение жестов на уровне активности

Обнаруживайте жесты на уровне активности, только когда не имеет значения, какая часть вашего пользовательского интерфейса находится в фокусе. Например, если вы хотите вызвать меню, когда пользователь касается сенсорной панели, независимо от того, какое представление имеет фокус, обработайте MotionEvent внутри действия.

Ниже приведен пример обнаружения жестов на уровне активности, в котором используется GestureDetector и реализуется GestureDetector.OnGestureListener для обработки распознанных жестов, которые затем обрабатываются и преобразуются в следующее:

  • TAP
  • SWIPE_FORWARD
  • SWIPE_BACKWARD
  • SWIPE_UP
  • SWIPE_DOWN

Котлин

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))
    }
}

Ява

  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);
       }
     }
   }
  }

Пример использования

Чтобы использовать обнаружение жестов на уровне активности, необходимо выполнить следующие задачи:

  1. Добавьте следующее объявление в файл манифеста внутри объявления приложения. Это позволяет вашему приложению получать MotionEvent в действии:
    <application>
    <!-- Copy below declaration into your manifest file -->
    <meta-data
      android:name="com.google.android.glass.TouchEnabledApplication"
      android:value="true" />
    </application>
    
  2. Переопределите метод dispatchTouchEvent(motionEvent) , чтобы передать события движения onTouchEvent(motionEvent) детектора жестов.
  3. GlassGestureDetector.OnGestureListener в своей деятельности.

Ниже приведен пример детектора жестов уровня активности:

Котлин

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)
    }
}

Ява

  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);
   }
  }

Аудио ввод

Glass Enterprise Edition 2 — это стандартное устройство на базе AOSP, поддерживающее основные источники звука .

В следующих источниках звука реализована расширенная обработка сигнала:

Распознавание голоса

Glass Enterprise Edition 2 поддерживает встроенную реализацию распознавания речи. Это поддерживается только для английского языка.

Стеклянное изображение распознавания голоса.

Пользовательский интерфейс распознавания речи ожидает, пока пользователи заговорят, а затем возвращает транскрибированный текст после того, как они закончат. Чтобы начать действие, выполните следующие действия:

  1. Вызовите startActivityForResult() с намерением ACTION_RECOGNIZE_SPEECH . Следующие дополнительные намерения поддерживаются при запуске действия:
  2. Переопределите обратный вызов onActivityResult() , чтобы получить транскрибированный текст из дополнительного намерения EXTRA_RESULTS , как показано в следующем примере кода. Этот обратный вызов вызывается, когда пользователь заканчивает говорить.

Котлин

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)
}

Ява

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);
}

Подробнее о реализации читайте в примере приложения для распознавания голоса .

Предвзятость по ключевым словам

Распознавание речи на Glass может быть предвзятым по списку ключевых слов. Предвзятость повышает точность распознавания ключевых слов. Чтобы включить смещение ключевых слов, используйте следующее:

Котлин

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

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

startActivityForResult(intent, SPEECH_REQUEST)

Ява

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

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

startActivityForResult(intent, SPEECH_REQUEST);

Голосовые команды

Голосовые команды позволяют пользователям выполнять действия из действий. Вы создаете голосовые команды с помощью стандартных API-интерфейсов меню Android, но пользователи могут вызывать пункты меню с помощью голосовых команд, а не касания.

Чтобы включить голосовые команды для определенного действия, выполните следующие действия:

  1. Вызовите getWindow().requestFeature(FEATURE_VOICE_COMMANDS) в нужном действии, чтобы включить голосовые команды. Если эта функция включена, значок микрофона появляется в левом нижнем углу экрана всякий раз, когда это действие получает фокус.
  2. Запросите разрешение RECORD_AUDIO в своем приложении.
  3. Переопределите onCreatePanelMenu() и раздуйте ресурс меню.
  4. Переопределите onContextItemSelected() для обработки обнаруженных голосовых команд.

Котлин

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)
        }
    }
}

Ява

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);
    }
  }
}

Ниже приведен пример ресурса меню, используемого предыдущим действием:

<?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>

Прочтите образец приложения для создания заметок, чтобы увидеть полный пример.

Перезагрузка списка голосовых команд

Вы можете динамически перезагружать список голосовых команд. Для этого замените ресурс menu в onCreatePanelMenu() или измените объект меню в onPreparePanel() . Чтобы применить изменения, вызовите метод invalidateOptionsMenu() .

Котлин

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()
}

Ява

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();
}

Решение AppCompatActivity

Чтобы перезагрузить список голосовых команд в действии, которое расширяет AppCompatActivity , используйте метод sendBroadcast() с действием намерения reload-voice-commands :

Котлин

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

Ява

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

Включение и отключение голосовых команд во время выполнения

Вы можете включать и отключать голосовые команды во время выполнения. Для этого верните соответствующее значение из onCreatePanelMenu() следующим образом:

  • Установите значение true , чтобы включить.
  • Установите значение false , чтобы отключить.

Режим отладки

Чтобы включить режим отладки для голосовых команд, вызовите getWindow().requestFeature(FEATURE_DEBUG_VOICE_COMMANDS) в нужном действии. Режим отладки активирует следующие функции:

  • Logcat содержит журнал с распознанной фразой для отладки.
  • Наложение пользовательского интерфейса отображается при обнаружении нераспознанной команды, как показано ниже:
  • Неопознанное командное изображение с распознаванием голоса в стекле.

Котлин

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
        )
    }
    .
    .
    .
}

Ява

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);
  }
  .
  .
  .
}

Подробнее о реализации читайте в примере приложения для перезагрузки голосовых команд .

Преобразование текста в речь (TTS)

Функция преобразования текста в речь преобразует цифровой текст в синтезированную речь. Дополнительные сведения см. в документации для разработчиков Android TextToSpeech .

В Glass EE2 установлен механизм преобразования текста в речь Google . Он установлен в качестве механизма TTS по умолчанию и работает в автономном режиме.

Следующие языки связаны с механизмом преобразования текста в речь Google:

бенгальский
китайский
чешский язык
датский
Немецкий
греческий
Английский
испанский
эстонский
финский
Французский
Гуджарати
хинди
венгерский язык
индонезийский
итальянский
Японский
яванский
австронезийский
австроазиатский
каннада
Корейский
малаялам
Норвежский
Голландский
польский
португальский
Русский
словацкий
Суданский
Шведский
тамильский
телугу
Тайский
турецкий
украинец
вьетнамский

Камера

Glass Enterprise Edition 2 оснащен 8-мегапиксельной камерой с фиксированным фокусом, апертурой f/2,4, соотношением сторон сенсора 4:3 и углом обзора 83° по диагонали (71° x 57° в альбомной ориентации). Мы рекомендуем использовать стандартный API CameraX или Camera2 .

Подробнее о реализации читайте в примере приложения камеры .

Кнопка камеры

Кнопка камеры — это физическая кнопка на шарнире устройства Glass Enterprise Edition 2. Его можно обрабатывать так же, как стандартное действие клавиатуры, и его можно идентифицировать по KeyEvent#KEYCODE_CAMERA .

Начиная с обновления ОС OPM1.200313.001 , намерения со следующими действиями отправляются из приложения Launcher:

Датчики

При разработке приложений в Glass EE2 разработчикам доступны различные датчики.

На Glass поддерживаются следующие стандартные сенсоры Android:

Следующие датчики Android не поддерживаются на Glass:

Система координат датчика Glass показана на следующем рисунке. Это относительно дисплея Glass. Для получения дополнительной информации см. Система координат датчика .

Здесь показана система координат датчика Glass относительно дисплея Glass.

Акселерометр, гироскоп и магнитометр расположены на оптической части устройства Glass, которую пользователи поворачивают, чтобы совместить устройство со своим прицелом. Вы не можете измерить угол модуля оптики напрямую, поэтому помните об этом, когда вы используете углы от этих датчиков для приложений, таких как направление по компасу.

Чтобы продлить срок службы батареи, прислушивайтесь к датчикам только тогда, когда они вам нужны. Учитывайте потребности и жизненный цикл приложения, когда решаете, когда начинать и когда прекращать слушать датчики.

Обратные вызовы событий датчика выполняются в потоке пользовательского интерфейса, поэтому события обрабатываются и возвращаются как можно быстрее. Если обработка занимает слишком много времени, поместите события датчика в очередь и используйте фоновый поток для их обработки.

50 Гц часто бывает достаточно для отслеживания движения головы.

Дополнительные сведения об использовании датчиков см. в руководстве для разработчиков Android .

Сервисы определения местоположения

Устройство Glass Enterprise Edition 2 не оснащено модулем GPS и не определяет местоположение пользователя. Однако в нем реализованы службы определения местоположения, которые необходимы для отображения списка ближайших сетей Wi-Fi и устройств Bluetooth.

Если у вашего приложения есть привилегии владельца устройства, вы можете использовать его для программного изменения значения соответствующего параметра безопасности:

Котлин

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()
    )
}

Ява

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));
}

Если вы используете стороннее решение MDM, решение MDM должно иметь возможность изменять эти параметры за вас.