ورودی ها و سنسورها

Android SDK به شما امکان می دهد به ورودی ها و حسگرهای مختلف موجود با Glass EE2 دسترسی داشته باشید. این صفحه نمای کلی از ویژگی های موجود، جزئیات پیاده سازی و نکات مفید را در اختیار شما قرار می دهد.

حرکات لمسی

می‌توانید از Android SDK برای فعال کردن دسترسی به داده‌های خام از صفحه لمسی Glass استفاده کنید. این کار از طریق یک آشکارساز اشاره انجام می شود که به طور خودکار ژست های رایج روی شیشه مانند ضربه زدن، پرت کردن، و اسکرول را تشخیص می دهد.

همچنین می‌توانید از این آشکارساز ژست‌ها در برنامه‌های خود برای حساب کردن ضربه، تند کشیدن به جلو، کشیدن انگشت به عقب و کشیدن انگشت به پایین استفاده کنید. این شبیه به دستگاه های قبلی Glass است.

بهتر است از این حرکات به روش های زیر استفاده کنید:

  • ضربه بزنید : تأیید یا وارد کنید.
  • تند کشیدن به جلو ، تند کشیدن به عقب : بین کارت‌ها و صفحه‌ها حرکت کنید.
  • تند کشیدن به پایین : به عقب یا خارج شوید.

برای جزئیات پیاده سازی، نمونه آشکارساز ژست را بخوانید.

ژست‌ها را با ردیاب ژست اندروید تشخیص دهید

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

برای جزئیات پیاده سازی، نمونه برنامه تشخیص صدا را بخوانید.

سوگیری برای کلمات کلیدی

تشخیص گفتار روی شیشه می تواند برای لیستی از کلمات کلیدی مغرضانه باشد. بایاسینگ دقت تشخیص کلمه کلیدی را افزایش می دهد. برای فعال کردن بایاس برای کلمات کلیدی، از موارد زیر استفاده کنید:

کاتلین

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 های منوی استاندارد اندروید می سازید، اما کاربران می توانند به جای لمس، آیتم های منو را با دستورات صوتی فراخوانی کنند.

برای فعال کردن دستورات صوتی برای یک فعالیت خاص، مراحل زیر را دنبال کنید:

  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 intent استفاده کنید:

کاتلین

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

جاوا

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

دستورات صوتی را در زمان اجرا فعال و غیرفعال کنید

می توانید دستورات صوتی را در زمان اجرا فعال یا غیرفعال کنید. برای انجام این کار، یک مقدار مناسب از onCreatePanelMenu() به صورت زیر برگردانید:

  • مقدار را روی true تنظیم کنید تا فعال شود.
  • مقدار را روی false قرار دهید تا غیرفعال شود.

حالت اشکال زدایی

برای فعال کردن حالت اشکال زدایی برای دستورات صوتی، getWindow().requestFeature(FEATURE_DEBUG_VOICE_COMMANDS) در فعالیت مورد نظر فراخوانی کنید. حالت Debug ویژگی های زیر را فعال می کند:

  • 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 Developers Documentation TextToSpeech دیدن کنید.

Glass EE2 موتور Google Text-to-Speech را نصب کرده است. به عنوان موتور پیش فرض TTS تنظیم شده است و به صورت آفلاین کار می کند.

مناطق زیر با موتور Google Text-to-Speech همراه هستند:

بنگالی
ماندارین چینی
کشور چک
دانمارکی
آلمانی
یونانی
انگلیسی
اسپانیایی
استونیایی
فنلاندی
فرانسوی
گجراتی
هندی
مجارستانی
اندونزیایی
ایتالیایی
ژاپنی
جاوه ای
آسترونزی
استروآسیایی
کانادا
کره ای
مالایایی
نروژی
هلندی
لهستانی
پرتغالی
روسی
اسلواکی
ساندانی
سوئدی
تامیل
تلوگو
تایلندی
ترکی
اوکراینی
ویتنامی

دوربین

Glass Enterprise Edition 2 مجهز به یک دوربین 8 مگاپیکسلی با فوکوس ثابت است که دارای دیافراگم f/2.4، نسبت ابعاد سنسور 4:3 و میدان دید مورب 83 درجه (71 درجه در 57 درجه در جهت افقی) است. توصیه می کنیم از CameraX یا Camera2 API استاندارد استفاده کنید.

برای جزئیات پیاده سازی، نمونه برنامه دوربین را بخوانید.

دکمه دوربین

دکمه دوربین، دکمه فیزیکی روی لولای دستگاه Glass Enterprise Edition 2 است. می توان آن را درست مانند یک عملکرد صفحه کلید استاندارد مدیریت کرد و با کد کلید KeyEvent#KEYCODE_CAMERA قابل شناسایی است.

از زمان به‌روزرسانی OPM1.200313.001 سیستم عامل، هدف‌هایی با اقدامات زیر از برنامه Launcher ارسال می‌شوند:

حسگرها

حسگرهای مختلفی برای توسعه دهندگان وجود دارد که برنامه های کاربردی را در Glass EE2 توسعه می دهند.

سنسورهای استاندارد اندروید زیر در Glass پشتیبانی می‌شوند:

سنسورهای Android زیر در Glass پشتیبانی نمی‌شوند:

سیستم مختصات حسگر شیشه ای در شکل زیر نشان داده شده است. این نسبت به صفحه نمایش شیشه ای است. برای اطلاعات بیشتر، به سیستم مختصات حسگر مراجعه کنید.

سیستم مختصات حسگر شیشه ای در اینجا نسبت به صفحه نمایش شیشه ای نشان داده شده است.

شتاب سنج، ژیروسکوپ و مغناطیس سنج بر روی غلاف اپتیک دستگاه Glass قرار دارند که کاربران با چرخاندن آن دستگاه را با دید خود هماهنگ می کنند. شما نمی توانید مستقیماً زاویه غلاف نوری را اندازه گیری کنید، بنابراین هنگام استفاده از زوایای این سنسورها برای برنامه هایی مانند عنوان قطب نما، از این موضوع آگاه باشید.

برای حفظ عمر باتری، فقط در صورت نیاز به سنسورها گوش دهید. هنگامی که تصمیم می گیرید چه زمانی گوش دادن به حسگرها را شروع کنید و چه زمانی را متوقف کنید، نیازها و چرخه عمر برنامه را در نظر بگیرید.

تماس‌های رویداد حسگر روی رشته UI اجرا می‌شوند، بنابراین رویدادها را در سریع‌ترین زمان ممکن پردازش کرده و برمی‌گرداند. اگر پردازش بیش از حد طول می کشد، رویدادهای حسگر را در یک صف قرار دهید و از یک رشته پس زمینه برای مدیریت آنها استفاده کنید.

50 هرتز اغلب یک نرخ نمونه برداری کافی برای ردیابی حرکت سر است.

برای اطلاعات بیشتر در مورد نحوه استفاده از حسگرها، به راهنمای برنامه‌نویس Android مراجعه کنید.

خدمات مکان یابی

دستگاه Glass Enterprise Edition 2 به ماژول GPS مجهز نیست و موقعیت مکانی کاربر را ارائه نمی دهد. با این حال، دارای خدمات مکان یابی است که برای نمایش لیستی از شبکه های Wi-Fi و دستگاه های بلوتوث اطراف ضروری است.

اگر برنامه شما دارای امتیازات مالک دستگاه است، می‌توانید از آن برای تغییر برنامه‌ای مقدار تنظیمات امن مربوطه استفاده کنید:

کاتلین

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 باید بتواند این تنظیمات را برای شما تغییر دهد.