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

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

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

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

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

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

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

Аудиовход

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

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

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

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

Изображение, полученное с помощью распознавания голоса на стекле.

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

  1. Вызовите startActivityForResult() с интентом ACTION_RECOGNIZE_SPEECH . При запуске активности поддерживаются следующие дополнительные параметры интента:
  2. Переопределите функцию обратного вызова onActivityResult() , чтобы получать расшифрованный текст из дополнительного объекта Intent 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)
}

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

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

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

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

Котлин

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

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

Голосовые команды позволяют пользователям выполнять действия из различных активностей. Голосовые команды создаются с помощью стандартных 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)
        }
    }
}

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

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

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

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

Решение AppCompatActivity

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

Котлин

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

Java

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

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

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

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

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

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

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

Котлин

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

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

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

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

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

В состав системы преобразования текста в речь 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()
    )
}

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

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