Pakiet Android SDK zapewnia dostęp do różnych wejść i czujników dostępnych w Glass EE2. Na tej stronie znajdziesz omówienie dostępnych funkcji, szczegóły implementacji i przydatne wskazówki.
Kliknięcia
Za pomocą pakietu Android SDK możesz włączyć dostęp do surowych danych z touchpada Glass. Jest to możliwe dzięki detektorowi gestów, który automatycznie wykrywa typowe gesty na urządzeniu Glass, takie jak kliknięcie, przesunięcie i przewijanie.
Możesz też używać tego detektora gestów w aplikacjach, aby uwzględniać kliknięcia, przesunięcia do przodu, do tyłu i w dół. Jest to podobne do poprzednich urządzeń Glass.
Najlepiej używać tych gestów w ten sposób:
- Kliknij: potwierdź lub wpisz.
- Przesuń do przodu, przesuń do tyłu: poruszaj się po kartach i ekranach.
- Przesuń w dół: cofnij lub wyjdź.
Szczegóły wdrażania znajdziesz w przykładowym detektorze gestów.
Wykrywanie gestów za pomocą detektora gestów Androida
Interfejs GestureDetector Androida umożliwia wykrywanie prostych i złożonych gestów, takich jak gesty wykonywane kilkoma palcami lub przewijanie.
Wykrywanie gestów na poziomie aktywności
Wykrywaj gesty na poziomie aktywności tylko wtedy, gdy nie ma znaczenia, która część interfejsu użytkownika jest aktywna.
Jeśli na przykład chcesz wyświetlić menu, gdy użytkownik dotknie touchpada, niezależnie od tego, które okno jest aktywne, obsłuż zdarzenie MotionEvent w aktywności.
Poniżej znajdziesz przykład wykrywania gestów na poziomie aktywności, które korzysta z interfejsu
GestureDetector i implementuje interfejs
GestureDetector.OnGestureListener do przetwarzania rozpoznanych gestów, które są następnie obsługiwane i tłumaczone na te działania:
TAPSWIPE_FORWARDSWIPE_BACKWARDSWIPE_UPSWIPE_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); } } } }
Przykładowe zastosowanie
Aby korzystać z wykrywania gestów na poziomie aktywności, musisz wykonać te czynności:
- Dodaj do pliku manifestu tę deklarację w deklaracji aplikacji. Dzięki temu aplikacja może otrzymywać
MotionEventw aktywności:<application> <!-- Copy below declaration into your manifest file --> <meta-data android:name="com.google.android.glass.TouchEnabledApplication" android:value="true" /> </application>
- Zastąp metodę aktywności
dispatchTouchEvent(motionEvent), aby przekazywać zdarzenia ruchu do metodyonTouchEvent(motionEvent)detektora gestów. - Zaimplementuj
GlassGestureDetector.OnGestureListenerw swojej aktywności.
Oto przykład detektora gestów na poziomie aktywności:
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); } }
Wejście audio
Glass Enterprise Edition 2 to standardowe urządzenie oparte na AOSP, które obsługuje podstawowe źródła dźwięku.
W przypadku tych źródeł dźwięku zastosowano zaawansowane przetwarzanie sygnału:
Rozpoznawanie głosu
Glass Enterprise Edition 2 obsługuje natywne rozpoznawanie mowy. Ta funkcja jest obsługiwana tylko w języku angielskim.
Interfejs rozpoznawania mowy czeka, aż użytkownik zacznie mówić, a potem zwraca transkrypcję tekstu. Aby rozpocząć aktywność, wykonaj te czynności:
- Wywołaj funkcję
startActivityForResult()z intencjąACTION_RECOGNIZE_SPEECH. Podczas rozpoczynania aktywności obsługiwane są te dodatkowe informacje o intencji: - Zastąp wywołanie zwrotne
onActivityResult(), aby otrzymać transkrybowany tekst z dodatku do intencjiEXTRA_RESULTS, jak pokazano w tym przykładowym kodzie. To wywołanie zwrotne jest wywoływane, gdy użytkownik skończy mówić.
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); }
Szczegóły wdrażania znajdziesz w przykładowej aplikacji do rozpoznawania mowy.
Preferowanie słów kluczowych
Rozpoznawanie mowy na Glass może być nastawione na listę słów kluczowych. Zwiększa to dokładność rozpoznawania słów kluczowych. Aby włączyć preferowanie słów kluczowych, użyj tego kodu:
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);
Polecenia głosowe
Polecenia głosowe umożliwiają użytkownikom wykonywanie działań w ramach aktywności. Polecenia głosowe tworzysz za pomocą standardowych interfejsów API menu Androida, ale użytkownicy mogą wywoływać elementy menu za pomocą poleceń głosowych zamiast dotyku.
Aby włączyć polecenia głosowe dla konkretnej aktywności, wykonaj te czynności:
- Zadzwoń
getWindow().requestFeature(FEATURE_VOICE_COMMANDS)w wybranej aktywności, aby włączyć polecenia głosowe. Gdy ta funkcja jest włączona, ikona mikrofonu pojawia się w lewym dolnym rogu ekranu za każdym razem, gdy ta aktywność jest aktywna. - Poproś o uprawnienie
RECORD_AUDIOw aplikacji. - Override
onCreatePanelMenu()i rozwiń zasób menu. - Zastąp
onContextItemSelected(), aby obsługiwać wykryte polecenia głosowe.
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); } } }
Oto przykład zasobu menu używanego przez poprzednie działanie:
<?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>
Pełny przykład znajdziesz w przykładowej aplikacji do robienia notatek.
Ponowne wczytywanie listy poleceń głosowych
Możesz dynamicznie przeładować listę poleceń głosowych. Aby to zrobić, zastąp zasób menu w metodzie onCreatePanelMenu() lub zmodyfikuj obiekt menu w metodzie onPreparePanel(). Aby zastosować zmiany, wywołaj metodę
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(); }
Rozwiązanie AppCompatActivity
Aby ponownie wczytać listę poleceń głosowych w aktywności, która rozszerza AppCompatActivity, użyj metody
sendBroadcast()
z działaniem intencji reload-voice-commands:
Kotlin
sendBroadcast(Intent("reload-voice-commands"))
Java
sendBroadcast(new Intent("reload-voice-commands"));
Włączanie i wyłączanie poleceń głosowych w czasie działania
Polecenia głosowe możesz włączać i wyłączać w czasie działania. Aby to zrobić, zwróć odpowiednią wartość z metody onCreatePanelMenu():
- Aby włączyć, ustaw wartość
true. - Aby wyłączyć, ustaw wartość
false.
Tryb debugowania
Aby włączyć tryb debugowania poleceń głosowych, wywołaj
getWindow().requestFeature(FEATURE_DEBUG_VOICE_COMMANDS)
w odpowiednim działaniu. Tryb debugowania aktywuje te funkcje:
- Logcat zawiera log z rozpoznaną frazą do debugowania.
- Gdy zostanie wykryte nierozpoznane polecenie, wyświetli się nakładka interfejsu, jak pokazano poniżej:
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); } . . . }
Szczegółowe informacje o wdrażaniu znajdziesz w przykładowych poleceniach głosowych do ponownego wczytywania aplikacji.
Zamiana tekstu na mowę (TTS)
Funkcja zamiany tekstu na mowę przekształca tekst cyfrowy na syntetyzowaną mowę. Więcej informacji znajdziesz w dokumentacji dla deweloperów aplikacji na Androida dotyczącej funkcji TextToSpeech.
Na urządzeniu Glass EE2 jest zainstalowany mechanizm zamiany tekstu na mowę od Google. Jest ustawiony jako domyślny silnik zamiany tekstu na mowę i działa offline.
Te języki są dostępne w mechanizmie zamiany tekstu na mowę Google:
|
bengalski, chiński mandaryński, czeski, duński, angielski, estoński, fiński, francuski, grecki, gudżarati, hindi, hiszpański, niemiecki, |
Węgierski Indonezyjski Włoski Japoński Jawajski Austronezyjski Austroazjatycki Kannada Koreański Malajalam Norweski Holenderski |
polski portugalski rosyjski słowacki sundajski szwedzki tamilski telugu tajski turecki ukraiński wietnamski |
Aparat
Glass Enterprise Edition 2 jest wyposażony w 8-megapikselowy aparat o stałej ostrości, przysłonie f/2.4, współczynniku proporcji czujnika 4:3 i przekątnej pola widzenia 83° (71° × 57° w orientacji poziomej). Zalecamy używanie standardowego interfejsu CameraX lub Camera2 API.
Szczegóły wdrażania znajdziesz w przykładowej aplikacji aparatu.
Przycisk aparatu
Przycisk aparatu to fizyczny przycisk na zawiasie urządzenia Glass Enterprise Edition 2.
Można je obsługiwać tak samo jak standardowe działanie klawiatury i identyfikować za pomocą kodu klawisza
KeyEvent#KEYCODE_CAMERA.
Od aktualizacji systemu operacyjnego OPM1.200313.001 aplikacja Launcher wysyła intencje z tymi działaniami:
MediaStore#ACTION_IMAGE_CAPTUREkrótkie naciśnięcie przycisku aparatu.MediaStore#ACTION_VIDEO_CAPTURE– przytrzymaj przycisk aparatu.
Czujniki
Podczas tworzenia aplikacji na Glass EE2 deweloperzy mają do dyspozycji różne czujniki.
Na Glass obsługiwane są te standardowe czujniki Androida:
-
TYPE_ACCELEROMETER -
TYPE_GRAVITY -
TYPE_GYROSCOPE -
TYPE_LIGHT -
TYPE_LINEAR_ACCELERATION -
TYPE_MAGNETIC_FIELD -
TYPE_ORIENTATION(wycofane) -
TYPE_ROTATION_VECTOR
Te czujniki Androida nie są obsługiwane na Glass:
Układ współrzędnych czujnika Glass jest przedstawiony na poniższej ilustracji. Jest on względny w stosunku do wyświetlacza Glass. Więcej informacji znajdziesz w artykule Układ współrzędnych czujnika.
Akcelerometr, żyroskop i magnetometr znajdują się w module optycznym urządzenia Glass, który użytkownicy obracają, aby dopasować urządzenie do swojego wzroku. Nie możesz bezpośrednio zmierzyć kąta modułu optycznego, więc pamiętaj o tym, gdy używasz kątów z tych czujników w aplikacjach, np. do określania kierunku kompasu.
Aby oszczędzać baterię, korzystaj z czujników tylko wtedy, gdy są potrzebne. Zastanów się, kiedy rozpocząć i zakończyć odczytywanie danych z czujników, biorąc pod uwagę potrzeby i cykl życia aplikacji.
Wywołania zwrotne zdarzeń czujnika są wykonywane w wątku interfejsu, więc przetwarzaj zdarzenia i zwracaj wyniki tak szybko, jak to możliwe. Jeśli przetwarzanie trwa zbyt długo, umieść zdarzenia z czujnika w kolejce i użyj wątku w tle, aby je obsłużyć.
Częstotliwość próbkowania 50 Hz jest często wystarczająca do śledzenia ruchu głowy.
Więcej informacji o korzystaniu z czujników znajdziesz w przewodniku dla deweloperów Androida.
Usługi lokalizacyjne
Urządzenie Glass Enterprise Edition 2 nie jest wyposażone w moduł GPS i nie podaje lokalizacji użytkownika. Ma jednak wdrożone usługi lokalizacyjne, które są niezbędne do wyświetlania listy pobliskich sieci Wi-Fi i urządzeń Bluetooth.
Jeśli Twoja aplikacja ma uprawnienia właściciela urządzenia, możesz jej użyć do programowego zmieniania wartości odpowiedniego bezpiecznego ustawienia:
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)); }
Jeśli korzystasz z rozwiązania MDM innej firmy, musi ono umożliwiać zmianę tych ustawień.