Browse Source

[kotlin] Migrated to Kotlin, updated to recent gradle, tested on EE10

master
Miguel Castiblanco 3 years ago
commit
3344890caf
  1. 5
      .gitignore
  2. 192
      LICENSE
  3. 24
      README.md
  4. 32
      app/build.gradle
  5. 90
      app/src/main/AndroidManifest.xml
  6. 161
      app/src/main/java/com/google/android/glass/sample/apidemo/ApiDemoActivity.kt
  7. 59
      app/src/main/java/com/google/android/glass/sample/apidemo/card/CardAdapter.kt
  8. 163
      app/src/main/java/com/google/android/glass/sample/apidemo/card/CardBuilderActivity.kt
  9. 195
      app/src/main/java/com/google/android/glass/sample/apidemo/card/CardScrollViewActivity.kt
  10. 68
      app/src/main/java/com/google/android/glass/sample/apidemo/card/EmbeddedCardLayoutActivity.kt
  11. 121
      app/src/main/java/com/google/android/glass/sample/apidemo/card/EmbeddedCardLayoutAdapter.kt
  12. 34
      app/src/main/java/com/google/android/glass/sample/apidemo/card/SimpleTableItem.kt
  13. 159
      app/src/main/java/com/google/android/glass/sample/apidemo/opengl/Cube.kt
  14. 100
      app/src/main/java/com/google/android/glass/sample/apidemo/opengl/CubeRenderer.kt
  15. 67
      app/src/main/java/com/google/android/glass/sample/apidemo/opengl/MenuActivity.kt
  16. 64
      app/src/main/java/com/google/android/glass/sample/apidemo/opengl/OpenGlService.kt
  17. 176
      app/src/main/java/com/google/android/glass/sample/apidemo/slider/SliderActivity.kt
  18. 47
      app/src/main/java/com/google/android/glass/sample/apidemo/theming/TextAppearanceActivity.kt
  19. 63
      app/src/main/java/com/google/android/glass/sample/apidemo/theming/TextAppearanceAdapter.kt
  20. 89
      app/src/main/java/com/google/android/glass/sample/apidemo/touchpad/ContinuousGesturesActivity.kt
  21. 87
      app/src/main/java/com/google/android/glass/sample/apidemo/touchpad/DiscreteGesturesActivity.kt
  22. 100
      app/src/main/java/com/google/android/glass/sample/apidemo/touchpad/SelectGestureDemoActivity.kt
  23. 238
      app/src/main/java/com/google/android/glass/sample/apidemo/touchpad/TouchpadView.kt
  24. 143
      app/src/main/java/com/google/android/glass/sample/apidemo/voicemenu/VoiceMenuActivity.kt
  25. BIN
      app/src/main/res/drawable-hdpi/ic_avatar_70.png
  26. BIN
      app/src/main/res/drawable-hdpi/ic_circle_blue.png
  27. BIN
      app/src/main/res/drawable-hdpi/ic_circle_green.png
  28. BIN
      app/src/main/res/drawable-hdpi/ic_circle_red.png
  29. BIN
      app/src/main/res/drawable-hdpi/ic_circle_yellow.png
  30. BIN
      app/src/main/res/drawable-hdpi/ic_glass_logo.png
  31. BIN
      app/src/main/res/drawable-hdpi/ic_phone_50.png
  32. BIN
      app/src/main/res/drawable-hdpi/ic_smile.png
  33. BIN
      app/src/main/res/drawable-hdpi/ic_stop.png
  34. BIN
      app/src/main/res/drawable-hdpi/ic_warning_150.png
  35. BIN
      app/src/main/res/drawable-hdpi/ic_wifi_150.png
  36. BIN
      app/src/main/res/drawable/beach.jpg
  37. BIN
      app/src/main/res/drawable/codemonkey1.jpg
  38. BIN
      app/src/main/res/drawable/codemonkey2.jpg
  39. BIN
      app/src/main/res/drawable/codemonkey3.jpg
  40. BIN
      app/src/main/res/drawable/codemonkey4.jpg
  41. BIN
      app/src/main/res/drawable/codemonkey5.jpg
  42. BIN
      app/src/main/res/drawable/codemonkey6.jpg
  43. BIN
      app/src/main/res/drawable/codemonkey7.jpg
  44. BIN
      app/src/main/res/drawable/codemonkey8.jpg
  45. BIN
      app/src/main/res/drawable/designer.jpg
  46. 20
      app/src/main/res/drawable/finger_trace_0.xml
  47. 20
      app/src/main/res/drawable/finger_trace_1.xml
  48. 20
      app/src/main/res/drawable/finger_trace_2.xml
  49. BIN
      app/src/main/res/drawable/product.jpg
  50. 32
      app/src/main/res/drawable/table_row_divider.xml
  51. 142
      app/src/main/res/layout/activity_continuous_gestures.xml
  52. 95
      app/src/main/res/layout/activity_discrete_gestures.xml
  53. 32
      app/src/main/res/layout/simple_table.xml
  54. 46
      app/src/main/res/layout/simple_table_row.xml
  55. 39
      app/src/main/res/layout/text_appearances_large.xml
  56. 39
      app/src/main/res/layout/text_appearances_medium.xml
  57. 39
      app/src/main/res/layout/text_appearances_small.xml
  58. 22
      app/src/main/res/menu/opengl_livecard.xml
  59. 55
      app/src/main/res/menu/voice_menu.xml
  60. 32
      app/src/main/res/values/colors.xml
  61. 23
      app/src/main/res/values/dimens.xml
  62. 118
      app/src/main/res/values/string.xml
  63. 26
      app/src/main/res/values/styles.xml
  64. 17
      app/src/main/res/xml/voice_trigger.xml
  65. 23
      build.gradle
  66. BIN
      gradle/wrapper/gradle-wrapper.jar
  67. 6
      gradle/wrapper/gradle-wrapper.properties
  68. 164
      gradlew
  69. 90
      gradlew.bat
  70. 1
      settings.gradle

5
.gitignore

@ -0,0 +1,5 @@
*.iml
local.properties
.idea/
.gradle/
build/

192
LICENSE

@ -0,0 +1,192 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and
distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright
owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities
that control, are controlled by, or are under common control with that entity.
For the purposes of this definition, "control" means (i) the power, direct or
indirect, to cause the direction or management of such entity, whether by
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising
permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including
but not limited to software source code, documentation source, and configuration
files.
"Object" form shall mean any form resulting from mechanical transformation or
translation of a Source form, including but not limited to compiled object code,
generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made
available under the License, as indicated by a copyright notice that is included
in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that
is based on (or derived from) the Work and for which the editorial revisions,
annotations, elaborations, or other modifications represent, as a whole, an
original work of authorship. For the purposes of this License, Derivative Works
shall not include works that remain separable from, or merely link (or bind by
name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version
of the Work and any modifications or additions to that Work or Derivative Works
thereof, that is intentionally submitted to Licensor for inclusion in the Work
by the copyright owner or by an individual or Legal Entity authorized to submit
on behalf of the copyright owner. For the purposes of this definition,
"submitted" means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems, and
issue tracking systems that are managed by, or on behalf of, the Licensor for
the purpose of discussing and improving the Work, but excluding communication
that is conspicuously marked or otherwise designated in writing by the copyright
owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
of whom a Contribution has been received by Licensor and subsequently
incorporated within the Work.
2. Grant of Copyright License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the Work and such
Derivative Works in Source or Object form.
3. Grant of Patent License.
Subject to the terms and conditions of this License, each Contributor hereby
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
irrevocable (except as stated in this section) patent license to make, have
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
such license applies only to those patent claims licensable by such Contributor
that are necessarily infringed by their Contribution(s) alone or by combination
of their Contribution(s) with the Work to which such Contribution(s) was
submitted. If You institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
Contribution incorporated within the Work constitutes direct or contributory
patent infringement, then any patent licenses granted to You under this License
for that Work shall terminate as of the date such litigation is filed.
4. Redistribution.
You may reproduce and distribute copies of the Work or Derivative Works thereof
in any medium, with or without modifications, and in Source or Object form,
provided that You meet the following conditions:
You must give any other recipients of the Work or Derivative Works a copy of
this License; and
You must cause any modified files to carry prominent notices stating that You
changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute,
all copyright, patent, trademark, and attribution notices from the Source form
of the Work, excluding those notices that do not pertain to any part of the
Derivative Works; and
If the Work includes a "NOTICE" text file as part of its distribution, then any
Derivative Works that You distribute must include a readable copy of the
attribution notices contained within such NOTICE file, excluding those notices
that do not pertain to any part of the Derivative Works, in at least one of the
following places: within a NOTICE text file distributed as part of the
Derivative Works; within the Source form or documentation, if provided along
with the Derivative Works; or, within a display generated by the Derivative
Works, if and wherever such third-party notices normally appear. The contents of
the NOTICE file are for informational purposes only and do not modify the
License. You may add Your own attribution notices within Derivative Works that
You distribute, alongside or as an addendum to the NOTICE text from the Work,
provided that such additional attribution notices cannot be construed as
modifying the License.
You may add Your own copyright statement to Your modifications and may provide
additional or different license terms and conditions for use, reproduction, or
distribution of Your modifications, or for any such Derivative Works as a whole,
provided Your use, reproduction, and distribution of the Work otherwise complies
with the conditions stated in this License.
5. Submission of Contributions.
Unless You explicitly state otherwise, any Contribution intentionally submitted
for inclusion in the Work by You to the Licensor shall be under the terms and
conditions of this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify the terms of
any separate license agreement you may have executed with Licensor regarding
such Contributions.
6. Trademarks.
This License does not grant permission to use the trade names, trademarks,
service marks, or product names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the NOTICE file.
7. Disclaimer of Warranty.
Unless required by applicable law or agreed to in writing, Licensor provides the
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
including, without limitation, any warranties or conditions of TITLE,
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
solely responsible for determining the appropriateness of using or
redistributing the Work and assume any risks associated with Your exercise of
permissions under this License.
8. Limitation of Liability.
In no event and under no legal theory, whether in tort (including negligence),
contract, or otherwise, unless required by applicable law (such as deliberate
and grossly negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special, incidental,
or consequential damages of any character arising as a result of this License or
out of the use or inability to use the Work (including but not limited to
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
any and all other commercial damages or losses), even if such Contributor has
been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability.
While redistributing the Work or Derivative Works thereof, You may choose to
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
other liability obligations and/or rights consistent with this License. However,
in accepting such obligations, You may act only on Your own behalf and on Your
sole responsibility, not on behalf of any other Contributor, and only if You
agree to indemnify, defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason of your
accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work
To apply the Apache License to your work, attach the following boilerplate
notice, with the fields enclosed by brackets "[]" replaced with your own
identifying information. (Don't include the brackets!) The text should be
enclosed in the appropriate comment syntax for the file format. We also
recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

24
README.md

@ -0,0 +1,24 @@
ApiDemo
=======
This sample is a gallery of some GDK APIs usage rewritten in Kotlin:
- Card and CardScrollView
- GestureDetector
- Theming with textAppearance
- OpenGL in a LiveCard
## Getting started
Check out our documentation to learn how to get started on
https://developers.google.com/glass/gdk/index
## Running the sample on Glass
On the command line:
$ ./gradlew clean build
$ adb install -r app/build/outputs/apk/debug/app-debug.apk
To start the sample, say "ok glass, show me a demo" from the Glass clock
screen.

32
app/build.gradle

@ -0,0 +1,32 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
repositories {
jcenter()
flatDir {
dirs 'prebuilt-libs'
}
}
android {
compileSdkVersion "Google Inc.:Glass Development Kit Preview:19"
buildToolsVersion "28.0.3"
defaultConfig {
minSdkVersion 19
targetSdkVersion 28
}
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

90
app/src/main/AndroidManifest.xml

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2013 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.glass.sample.apidemo"
android:versionCode="1"
android:versionName="1.0"
>
<!-- For free-style voice trigger and voice menus. -->
<uses-permission android:name="com.google.android.glass.permission.DEVELOPMENT"/>
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<application>
<activity android:name=".ApiDemoActivity"
android:icon="@drawable/ic_glass_logo"
android:label="@string/app_name"
android:exported="true" >
<intent-filter>
<action android:name="com.google.android.glass.action.VOICE_TRIGGER" />
</intent-filter>
<meta-data android:name="com.google.android.glass.VoiceTrigger"
android:resource="@xml/voice_trigger"
/>
</activity>
<activity android:name=".card.CardBuilderActivity"
android:exported="true"
/>
<activity android:name=".card.EmbeddedCardLayoutActivity"
android:exported="true"
/>
<activity android:name=".card.CardScrollViewActivity"
android:exported="true"
/>
<activity android:name=".touchpad.SelectGestureDemoActivity"
android:exported="true"
/>
<activity android:name=".touchpad.DiscreteGesturesActivity"
android:exported="true"
/>
<activity android:name=".touchpad.ContinuousGesturesActivity"
android:exported="true"
/>
<activity android:name=".theming.TextAppearanceActivity"
android:exported="true"
/>
<activity android:name=".opengl.MenuActivity"
android:exported="true"
android:theme="@style/MenuTheme"
/>
<service
android:name=".opengl.OpenGlService"
android:exported="true"
/>
<activity android:name=".voicemenu.VoiceMenuActivity"
android:exported="true"
/>
<activity android:name=".slider.SliderActivity"
android:exported="true"
/>
</application>
</manifest>

161
app/src/main/java/com/google/android/glass/sample/apidemo/ApiDemoActivity.kt

@ -0,0 +1,161 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.glass.sample.apidemo
import com.google.android.glass.media.Sounds
import com.google.android.glass.sample.apidemo.card.CardAdapter
import com.google.android.glass.sample.apidemo.card.CardBuilderActivity
import com.google.android.glass.sample.apidemo.card.CardScrollViewActivity
import com.google.android.glass.sample.apidemo.card.EmbeddedCardLayoutActivity
import com.google.android.glass.sample.apidemo.opengl.OpenGlService
import com.google.android.glass.sample.apidemo.slider.SliderActivity
import com.google.android.glass.sample.apidemo.theming.TextAppearanceActivity
import com.google.android.glass.sample.apidemo.touchpad.SelectGestureDemoActivity
import com.google.android.glass.sample.apidemo.voicemenu.VoiceMenuActivity
import com.google.android.glass.widget.CardBuilder
import com.google.android.glass.widget.CardScrollAdapter
import com.google.android.glass.widget.CardScrollView
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.media.AudioManager
import android.os.Bundle
import android.util.Log
import android.widget.AdapterView
import java.util.ArrayList
/**
* Creates a card scroll view with examples of different GDK APIs.
*
*
* 1. CardBuilder API
* 1. CardScrollView API
* 1. GestureDetector
* 1. textAppearance[Large|Medium|Small]
* 1. OpenGL LiveCard
* 1. VoiceMenu
*
*/
class ApiDemoActivity : Activity() {
private lateinit var mAdapter: CardScrollAdapter
// Visible for testing.
private lateinit var scroller: CardScrollView
override fun onCreate(bundle: Bundle?) {
super.onCreate(bundle)
mAdapter = CardAdapter(createCards(this))
print("CARDS CREATED ${mAdapter.count}")
scroller = CardScrollView(this)
scroller.adapter = mAdapter
setContentView(scroller)
setCardScrollerListener()
}
/**
* Create list of API demo cards.
*/
private fun createCards(context: Context): MutableList<CardBuilder> {
val cards = ArrayList<CardBuilder>()
cards.add(CARD_BUILDER, CardBuilder(context, CardBuilder.Layout.TEXT)
.setText(R.string.text_card_builder))
cards.add(CARD_BUILDER_EMBEDDED_LAYOUT, CardBuilder(context, CardBuilder.Layout.TEXT)
.setText(R.string.text_card_builder_embedded_layout))
cards.add(CARD_SCROLL_VIEW, CardBuilder(context, CardBuilder.Layout.TEXT)
.setText(R.string.text_card_scroll_view))
cards.add(GESTURE_DETECTOR, CardBuilder(context, CardBuilder.Layout.TEXT)
.setText(R.string.text_gesture_detector))
cards.add(TEXT_APPEARANCE, CardBuilder(context, CardBuilder.Layout.TEXT)
.setText(R.string.text_text_appearance))
cards.add(OPENGL, CardBuilder(context, CardBuilder.Layout.TEXT)
.setText(R.string.text_opengl))
cards.add(VOICE_MENU, CardBuilder(context, CardBuilder.Layout.TEXT)
.setText(R.string.text_voice_menu))
cards.add(SLIDER, CardBuilder(context, CardBuilder.Layout.TEXT)
.setText(R.string.text_slider))
return cards
}
override fun onResume() {
super.onResume()
scroller.activate()
}
override fun onPause() {
scroller.deactivate()
super.onPause()
}
/**
* Different type of activities can be shown, when tapped on a card.
*/
private fun setCardScrollerListener() {
scroller.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, id ->
Log.d(TAG, "Clicked view at position $position, row-id $id")
var soundEffect = Sounds.TAP
when (position) {
CARD_BUILDER -> startActivity(Intent(this@ApiDemoActivity, CardBuilderActivity::class.java))
CARD_BUILDER_EMBEDDED_LAYOUT -> startActivity(Intent(
this@ApiDemoActivity, EmbeddedCardLayoutActivity::class.java))
CARD_SCROLL_VIEW -> startActivity(Intent(this@ApiDemoActivity,
CardScrollViewActivity::class.java))
GESTURE_DETECTOR -> startActivity(Intent(this@ApiDemoActivity,
SelectGestureDemoActivity::class.java))
TEXT_APPEARANCE -> startActivity(Intent(this@ApiDemoActivity,
TextAppearanceActivity::class.java))
OPENGL -> startService(Intent(this@ApiDemoActivity, OpenGlService::class.java))
VOICE_MENU -> startActivity(Intent(this@ApiDemoActivity, VoiceMenuActivity::class.java))
SLIDER -> startActivity(Intent(this@ApiDemoActivity, SliderActivity::class.java))
else -> {
soundEffect = Sounds.ERROR
Log.d(TAG, "Don't show anything")
}
}
// Play sound.
val am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
am.playSoundEffect(soundEffect)
}
}
companion object {
private val TAG = ApiDemoActivity::class.java.simpleName
// Index of api demo cards.
// Visible for testing.
internal const val CARD_BUILDER = 0
internal const val CARD_BUILDER_EMBEDDED_LAYOUT = 1
internal const val CARD_SCROLL_VIEW = 2
internal const val GESTURE_DETECTOR = 3
internal const val TEXT_APPEARANCE = 4
internal const val OPENGL = 5
internal const val VOICE_MENU = 6
internal const val SLIDER = 7
}
}

59
app/src/main/java/com/google/android/glass/sample/apidemo/card/CardAdapter.kt

@ -0,0 +1,59 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.glass.sample.apidemo.card
import com.google.android.glass.widget.CardBuilder
import com.google.android.glass.widget.CardScrollAdapter
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
/**
* Adapter class that handles list of cards.
*/
open class CardAdapter(internal val mCards: MutableList<CardBuilder>) : CardScrollAdapter() {
override fun getCount(): Int {
return mCards.size
}
override fun getItem(position: Int): Any {
return mCards[position]
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
return mCards[position].getView(convertView, parent)
}
override fun getViewTypeCount(): Int {
return CardBuilder.getViewTypeCount()
}
override fun getItemViewType(position: Int): Int {
return mCards[position].itemViewType
}
override fun getPosition(item: Any): Int {
for (i in mCards.indices) {
if (getItem(i) == item) {
return i
}
}
return AdapterView.INVALID_POSITION
}
}

163
app/src/main/java/com/google/android/glass/sample/apidemo/card/CardBuilderActivity.kt

@ -0,0 +1,163 @@
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.glass.sample.apidemo.card
import com.google.android.glass.sample.apidemo.R
import com.google.android.glass.widget.CardBuilder
import com.google.android.glass.widget.CardScrollView
import android.app.Activity
import android.content.Context
import android.os.Bundle
import java.util.ArrayList
/**
* Creates a card scroll view with examples of different image layout cards.
*/
class CardBuilderActivity : Activity() {
private lateinit var mCardScroller: CardScrollView
override fun onCreate(bundle: Bundle?) {
super.onCreate(bundle)
mCardScroller = CardScrollView(this)
mCardScroller.adapter = CardAdapter(createCards(this))
setContentView(mCardScroller)
}
/**
* Creates list of cards that showcase different type of [CardBuilder] API.
*/
private fun createCards(context: Context): MutableList<CardBuilder> {
val cards = ArrayList<CardBuilder>()
// Add cards that demonstrate TEXT layouts.
cards.add(CardBuilder(context, CardBuilder.Layout.TEXT)
.setText(R.string.text_card_text_not_fixed)
.setFootnote(R.string.text_card_footnote)
.setTimestamp(R.string.text_card_timestamp)
.setAttributionIcon(R.drawable.ic_smile))
cards.add(createCardWithImages(context, CardBuilder.Layout.TEXT)
.setText(R.string.text_card_text_with_images)
.setFootnote(R.string.text_card_footnote)
.setTimestamp(R.string.text_card_timestamp)
.setAttributionIcon(R.drawable.ic_smile))
cards.add(CardBuilder(context, CardBuilder.Layout.TEXT_FIXED)
.setText(R.string.text_card_text_fixed)
.setFootnote(R.string.text_card_footnote)
.setTimestamp(R.string.text_card_timestamp)
.setAttributionIcon(R.drawable.ic_smile))
cards.add(CardBuilder(context, CardBuilder.Layout.TEXT)
.setText(R.string.text_card_text_stack_indicator)
.showStackIndicator(true)
.setAttributionIcon(R.drawable.ic_smile))
// Add cards that demonstrate COLUMNS layouts.
cards.add(createCardWithImages(context, CardBuilder.Layout.COLUMNS)
.setText(R.string.text_card_columns_not_fixed)
.setFootnote(R.string.text_card_footnote)
.setTimestamp(R.string.text_card_timestamp)
.setAttributionIcon(R.drawable.ic_smile))
cards.add(CardBuilder(context, CardBuilder.Layout.COLUMNS)
.setText(R.string.text_card_columns_with_icon)
.setIcon(R.drawable.ic_wifi_150)
.setFootnote(R.string.text_card_footnote)
.setTimestamp(R.string.text_card_timestamp)
.setAttributionIcon(R.drawable.ic_smile))
cards.add(createCardWithImages(context, CardBuilder.Layout.COLUMNS)
.setText(R.string.text_card_columns_fixed)
.setFootnote(R.string.text_card_footnote)
.setTimestamp(R.string.text_card_timestamp)
.setAttributionIcon(R.drawable.ic_smile))
// Add cards that demonstrate CAPTION layouts.
cards.add(CardBuilder(context, CardBuilder.Layout.CAPTION)
.addImage(R.drawable.beach)
.setText(R.string.text_card_caption)
.setFootnote(R.string.text_card_footnote)
.setTimestamp(R.string.text_card_timestamp)
.setAttributionIcon(R.drawable.ic_smile))
cards.add(CardBuilder(context, CardBuilder.Layout.CAPTION)
.addImage(R.drawable.beach)
.setText(R.string.text_card_caption_with_icon)
.setIcon(R.drawable.ic_avatar_70)
.setFootnote(R.string.text_card_footnote)
.setTimestamp(R.string.text_card_timestamp)
.setAttributionIcon(R.drawable.ic_smile))
// Add cards that demonstrate TITLE layouts.
cards.add(CardBuilder(context, CardBuilder.Layout.TITLE)
.addImage(R.drawable.beach)
.setText(R.string.text_card_title))
cards.add(CardBuilder(context, CardBuilder.Layout.TITLE)
.addImage(R.drawable.beach)
.setText(R.string.text_card_title_icon)
.setIcon(R.drawable.ic_phone_50))
// Add cards that demonstrate MENU layouts.
cards.add(CardBuilder(context, CardBuilder.Layout.MENU)
.setText(R.string.text_card_menu)
.setFootnote(R.string.text_card_menu_description)
.setIcon(R.drawable.ic_phone_50))
// Add cards that demonstrate ALERT layouts.
cards.add(CardBuilder(context, CardBuilder.Layout.ALERT)
.setText(R.string.text_card_alert)
.setFootnote(R.string.text_card_alert_description)
.setIcon(R.drawable.ic_warning_150))
// Add cards that demonstrate AUTHOR layouts.
cards.add(CardBuilder(context, CardBuilder.Layout.AUTHOR)
.setText(R.string.text_card_author_text)
.setIcon(R.drawable.ic_avatar_70)
.setHeading(R.string.text_card_author_heading)
.setSubheading(R.string.text_card_author_subheading)
.setFootnote(R.string.text_card_footnote)
.setTimestamp(R.string.text_card_timestamp)
.setAttributionIcon(R.drawable.ic_smile))
return cards
}
/**
* Returns a new [CardBuilder] with the specified layout and adds five images to it for
* the mosaic.
*/
private fun createCardWithImages(context: Context, layout: CardBuilder.Layout): CardBuilder {
val card = CardBuilder(context, layout)
card.addImage(R.drawable.codemonkey1)
card.addImage(R.drawable.codemonkey2)
card.addImage(R.drawable.codemonkey3)
card.addImage(R.drawable.codemonkey4)
card.addImage(R.drawable.codemonkey5)
card.addImage(R.drawable.codemonkey6)
card.addImage(R.drawable.codemonkey7)
card.addImage(R.drawable.codemonkey8)
return card
}
override fun onResume() {
super.onResume()
mCardScroller.activate()
}
override fun onPause() {
mCardScroller.deactivate()
super.onPause()
}
}

195
app/src/main/java/com/google/android/glass/sample/apidemo/card/CardScrollViewActivity.kt

@ -0,0 +1,195 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.glass.sample.apidemo.card
import com.google.android.glass.media.Sounds
import com.google.android.glass.sample.apidemo.R
import com.google.android.glass.widget.CardBuilder
import com.google.android.glass.widget.CardScrollView
import android.app.Activity
import android.content.Context
import android.media.AudioManager
import android.os.Bundle
import android.widget.AdapterView
import java.util.ArrayList
import java.util.Random
/**
* Creates a card scroll view with various examples of its API.
*/
class CardScrollViewActivity : Activity() {
private val mRandom = Random()
private var mCardScroller: CardScrollView? = null
private var mAdapter: CardAdapterWithMutations? = null
/** Actions associated with cards. */
private enum class Action constructor(internal val textId: Int, internal val imageId: Int) {
DELETION_HERE(R.string.text_card_tap_to_delete, R.drawable.codemonkey1),
NAVIGATION_TO_BEGIN(R.string.text_card_tap_to_navigate_begin, R.drawable.codemonkey2),
NAVIGATION_TO_END(R.string.text_card_tap_to_navigate_end, R.drawable.codemonkey3),
INSERTION_AT_BEGIN(R.string.text_card_tap_to_insert_begin, R.drawable.codemonkey4),
INSERTION_BEFORE(R.string.text_card_tap_to_insert_before, R.drawable.codemonkey5),
INSERTION_AFTER(R.string.text_card_tap_to_insert_after, R.drawable.codemonkey6),
INSERTION_AT_END(R.string.text_card_tap_to_insert_end, R.drawable.codemonkey7),
NO_ACTION(R.string.text_card_no_action, R.drawable.codemonkey8)
}
/**
* Adapter class that handles list of cards with associated actions and
* allows for mutations without notifying the adapter of the data change yet
* (through method [.notifyDataSetChanged]). Useful to demonstrate
* mutation animations.
*/
private inner class CardAdapterWithMutations : CardAdapter(ArrayList()) {
private val mActions: MutableList<Action>
init {
mActions = ArrayList()
}
/** Inserts a card into the adapter, without notifying. */
fun insertCardWithoutNotification(position: Int, card: CardBuilder, action: Action) {
mCards.add(position, card)
mActions.add(position, action)
}
/** Deletes card from the adapter, without notifying. */
fun deleteCardWithoutNotification(position: Int) {
mCards.removeAt(position)
mActions.removeAt(position)
}
/** Returns the action associated with the card at position. */
fun getActionAt(position: Int): Action {
return mActions[position]
}
}
override fun onCreate(bundle: Bundle?) {
super.onCreate(bundle)
mCardScroller = CardScrollView(this)
setupAdapter()
setupClickListener()
setContentView(mCardScroller)
}
/**
* Sets up adapter.
*/
private fun setupAdapter() {
mAdapter = CardAdapterWithMutations()
// Insert initial cards, one of each kind.
for (i in 0..7) {
val action = Action.values()[i]
val card = CardBuilder(this, CardBuilder.Layout.COLUMNS)
card.setText(action.textId).addImage(action.imageId)
mAdapter!!.insertCardWithoutNotification(i, card, action)
}
// Setting adapter notifies the card scroller of new content.
mCardScroller!!.adapter = mAdapter
}
/**
* Sets up click listener.
*/
private fun setupClickListener() {
mCardScroller!!.onItemClickListener = AdapterView.OnItemClickListener { _, _, position, _ ->
val am = getSystemService(Context.AUDIO_SERVICE) as AudioManager
when (mAdapter!!.getActionAt(position)) {
Action.DELETION_HERE -> {
am.playSoundEffect(Sounds.TAP)
deleteCard(position)
}
Action.NAVIGATION_TO_BEGIN -> {
am.playSoundEffect(Sounds.TAP)
navigateToCard(0)
}
Action.NAVIGATION_TO_END -> {
am.playSoundEffect(Sounds.TAP)
navigateToCard(mAdapter!!.count - 1)
}
Action.INSERTION_AT_BEGIN -> {
am.playSoundEffect(Sounds.TAP)
insertNewCard(0)
}
Action.INSERTION_BEFORE -> {
am.playSoundEffect(Sounds.TAP)
insertNewCard(position)
}
Action.INSERTION_AFTER -> {
am.playSoundEffect(Sounds.TAP)
insertNewCard(position + 1)
}
Action.INSERTION_AT_END -> {
am.playSoundEffect(Sounds.TAP)
insertNewCard(mAdapter!!.count)
}
else -> am.playSoundEffect(Sounds.DISALLOWED)
}
}
}
/**
* Deletes a card at the given position using proper insertion animation
* (the card scroller will animate the old card from view).
*/
private fun deleteCard(position: Int) {
// Delete card in the adapter, but don't call notifyDataSetChanged() yet.
// Instead, request proper animation for deleted card from card scroller,
// which will notify the adapter at the right time during the animation.
mAdapter!!.deleteCardWithoutNotification(position)
mCardScroller!!.animate(position, CardScrollView.Animation.DELETION)
}
/** Navigates to card at given position. */
private fun navigateToCard(position: Int) {
mCardScroller!!.animate(position, CardScrollView.Animation.NAVIGATION)
}
/**
* Inserts a new card at the given position using proper insertion animation
* (the card scroller will animate to the new card).
*/
private fun insertNewCard(position: Int) {
// Insert new card in the adapter, but don't call notifyDataSetChanged()
// yet. Instead, request proper animation to inserted card from card scroller,
// which will notify the adapter at the right time during the animation.
val card = CardBuilder(this, CardBuilder.Layout.COLUMNS)
val action = Action.values()[mRandom.nextInt(8)]
card.setText(action.textId).addImage(action.imageId)
mAdapter!!.insertCardWithoutNotification(position, card, action)
mCardScroller!!.animate(position, CardScrollView.Animation.INSERTION)
}
override fun onResume() {
super.onResume()
mCardScroller!!.activate()
}
override fun onPause() {
mCardScroller!!.deactivate()
super.onPause()
}
}

68
app/src/main/java/com/google/android/glass/sample/apidemo/card/EmbeddedCardLayoutActivity.kt

@ -0,0 +1,68 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.glass.sample.apidemo.card
import com.google.android.glass.sample.apidemo.R
import com.google.android.glass.widget.CardScrollView
import android.app.Activity
import android.os.Bundle
import java.util.ArrayList
/**
* Creates a card scroll view that shows an example of using a custom embedded layout in a
* `CardBuilder`.
*/
class EmbeddedCardLayoutActivity : Activity() {
private lateinit var mCardScroller: CardScrollView
override fun onCreate(bundle: Bundle?) {
super.onCreate(bundle)
mCardScroller = CardScrollView(this)
mCardScroller.adapter = EmbeddedCardLayoutAdapter(this, createItems())
setContentView(mCardScroller)
}
/** Creates some sample items that will be displayed on cards in the card scroll view. */
private fun createItems(): List<SimpleTableItem> {
val items = ArrayList<SimpleTableItem>()
items.add(SimpleTableItem(R.drawable.ic_circle_blue, "Water", "8 oz"))
items.add(SimpleTableItem(R.drawable.ic_circle_yellow, "Eggs, large", "2"))
items.add(SimpleTableItem(R.drawable.ic_circle_red, "Ground beef", "4 oz"))
items.add(SimpleTableItem(R.drawable.ic_circle_green, "Brussel sprouts", "1 cup"))
items.add(SimpleTableItem(R.drawable.ic_circle_green, "Celery", "1 stalk"))
items.add(SimpleTableItem(R.drawable.ic_circle_red, "Beef jerky", "8 strips"))
items.add(SimpleTableItem(R.drawable.ic_circle_yellow, "Almonds", "3 handfuls"))
items.add(SimpleTableItem(
R.drawable.ic_circle_red, "Strawberry fruit leather", "2.5 miles"))
return items
}
override fun onResume() {
super.onResume()
mCardScroller.activate()
}
override fun onPause() {
mCardScroller.deactivate()
super.onPause()
}
}

121
app/src/main/java/com/google/android/glass/sample/apidemo/card/EmbeddedCardLayoutAdapter.kt

@ -0,0 +1,121 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.glass.sample.apidemo.card
import com.google.android.glass.sample.apidemo.R
import com.google.android.glass.widget.CardBuilder
import com.google.android.glass.widget.CardScrollAdapter
import android.content.Context
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ImageView
import android.widget.TextView
/**
* Populates views in a `CardScrollView` with cards built from custom embedded layouts to
* represent items in a simple table.
*/
class EmbeddedCardLayoutAdapter
/** Initializes a new adapter with the specified context and list of items. */
(private val mContext: Context, private val mItems: List<SimpleTableItem>) : CardScrollAdapter() {
override fun getViewTypeCount(): Int {
return 1
}
override fun getItemViewType(position: Int): Int {
return 0
}
override fun getCount(): Int {
// Compute the number of cards needed to display the items with 4 per card (rounding up to
// capture the remainder).
return Math.ceil(mItems.size.toDouble() / ITEMS_PER_CARD).toInt()
}
override fun getItem(position: Int): Any? {
return null
}
override fun getPosition(item: Any): Int {
return AdapterView.INVALID_POSITION
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val card = CardBuilder(mContext, CardBuilder.Layout.EMBED_INSIDE)
.setEmbeddedLayout(R.layout.simple_table)
.setFootnote(R.string.text_card_embedded_footnote)
.setTimestamp(R.string.text_card_embedded_timestamp)
val view = card.getView(convertView, parent)
// Get a reference to an embedded view from the custom layout and then manipulate it.
val tableView = view.findViewById(R.id.simple_table) as ViewGroup
populateTableRows(position, tableView)
return view
}
/** Populates all of the rows in the card at the specified position. */
private fun populateTableRows(position: Int, tableView: ViewGroup) {
val startItemIndex = position * ITEMS_PER_CARD
val endItemIndex = Math.min(startItemIndex + ITEMS_PER_CARD, mItems.size)
for (i in 0 until ITEMS_PER_CARD) {
val itemIndex = startItemIndex + i
val rowView = tableView.getChildAt(i) as ViewGroup
// The layout contains four fixed rows, so we need to hide the later ones if there are
// not four items on this card. We need to make sure to update the visibility in both
// cases though if the card has been recycled.
if (itemIndex < endItemIndex) {
val item = mItems[itemIndex]
populateTableRow(item, rowView)
rowView.visibility = View.VISIBLE
} else {
rowView.visibility = View.INVISIBLE
}
}
}
/** Populates a row in the table with the specified item data. */
private fun populateTableRow(item: SimpleTableItem, rowView: ViewGroup) {
val imageView = rowView.getChildAt(IMAGE_VIEW_INDEX) as ImageView
val primaryTextView = rowView.getChildAt(PRIMARY_TEXT_VIEW_INDEX) as TextView
val secondaryTextView = rowView.getChildAt(SECONDARY_TEXT_VIEW_INDEX) as TextView
imageView.setImageResource(item.iconResId)
primaryTextView.text = item.primaryText
secondaryTextView.text = item.secondaryText
}
companion object {
/** The maximum number of items that fit on a card. */
private const val ITEMS_PER_CARD = 4
/** Index of the [ImageView] containing the icon in a table row. */
private const val IMAGE_VIEW_INDEX = 0
/** Index of the [TextView] containing the primary text in a table row. */
private const val PRIMARY_TEXT_VIEW_INDEX = 1
/** Index of the [TextView] containing the secondary text in a table row. */
private const val SECONDARY_TEXT_VIEW_INDEX = 2
}
}

34
app/src/main/java/com/google/android/glass/sample/apidemo/card/SimpleTableItem.kt

@ -0,0 +1,34 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.glass.sample.apidemo.card
/**
* Simple data object used to represent items in a table, which are converted into views by
* [EmbeddedCardLayoutAdapter].
*/
data class SimpleTableItem
/**
* Initializes a new `SimpleTableItem` with the specified icon, primary text, and
* secondary text.
*/
(
/** The image resource ID associated with the table item. */
val iconResId: Int,
/** The primary text associated with the table item. */
val primaryText: CharSequence,
/** The secondary text associated with the table item. */
val secondaryText: CharSequence)

159
app/src/main/java/com/google/android/glass/sample/apidemo/opengl/Cube.kt

@ -0,0 +1,159 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.glass.sample.apidemo.opengl
import android.opengl.GLES20
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
/**
* Renders a 3D Cube using OpenGL ES 2.0.
*
* For more information on how to use OpenGL ES 2.0 on Android, see the
* [
* Displaying Graphics with OpenGL ES](//developer.android.com/training/graphics/opengl/index.html) developer guide.
*/
class Cube {
/** Vertex size in bytes. */
private val VERTEX_STRIDE = COORDS_PER_VERTEX * 4
/** Color size in bytes. */
private val COLOR_STRIDE = VALUES_PER_COLOR * 4
private val mVertexBuffer: FloatBuffer
private val mColorBuffer: FloatBuffer
private val mIndexBuffer: ByteBuffer
private val mProgram: Int
private val mPositionHandle: Int
private val mColorHandle: Int
private val mMVPMatrixHandle: Int
init {
var byteBuffer = ByteBuffer.allocateDirect(VERTICES.size * 4)
byteBuffer.order(ByteOrder.nativeOrder())
mVertexBuffer = byteBuffer.asFloatBuffer()
mVertexBuffer.put(VERTICES)
mVertexBuffer.position(0)
byteBuffer = ByteBuffer.allocateDirect(COLORS.size * 4)
byteBuffer.order(ByteOrder.nativeOrder())
mColorBuffer = byteBuffer.asFloatBuffer()
mColorBuffer.put(COLORS)
mColorBuffer.position(0)
mIndexBuffer = ByteBuffer.allocateDirect(INDICES.size)
mIndexBuffer.put(INDICES)
mIndexBuffer.position(0)
mProgram = GLES20.glCreateProgram()
GLES20.glAttachShader(mProgram, loadShader(GLES20.GL_VERTEX_SHADER, VERTEX_SHADER_CODE))
GLES20.glAttachShader(
mProgram, loadShader(GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_CODE))
GLES20.glLinkProgram(mProgram)
mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition")
mColorHandle = GLES20.glGetAttribLocation(mProgram, "vColor")
mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix")
}
/**
* Encapsulates the OpenGL ES instructions for drawing this shape.
*
* @param mvpMatrix The Model View Project matrix in which to draw this shape
*/
fun draw(mvpMatrix: FloatArray) {
// Add program to OpenGL environment.
GLES20.glUseProgram(mProgram)
// Prepare the cube coordinate data.
GLES20.glEnableVertexAttribArray(mPositionHandle)
GLES20.glVertexAttribPointer(
mPositionHandle, 3, GLES20.GL_FLOAT, false, VERTEX_STRIDE, mVertexBuffer)
// Prepare the cube color data.
GLES20.glEnableVertexAttribArray(mColorHandle)
GLES20.glVertexAttribPointer(
mColorHandle, 4, GLES20.GL_FLOAT, false, COLOR_STRIDE, mColorBuffer)
// Apply the projection and view transformation.
GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0)
// Draw the cube.
GLES20.glDrawElements(
GLES20.GL_TRIANGLES, INDICES.size, GLES20.GL_UNSIGNED_BYTE, mIndexBuffer)
// Disable vertex arrays.
GLES20.glDisableVertexAttribArray(mPositionHandle)
GLES20.glDisableVertexAttribArray(mColorHandle)
}
companion object {
/** Cube vertices */
private val VERTICES = floatArrayOf(-0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f, -0.5f, -0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f, 0.5f, 0.5f, -0.5f, 0.5f, 0.5f)
/** Vertex colors. */
private val COLORS = floatArrayOf(0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f)
/** Order to draw vertices as triangles. */
private val INDICES = byteArrayOf(0, 1, 3, 3, 1, 2, // Front face.
0, 1, 4, 4, 5, 1, // Bottom face.
1, 2, 5, 5, 6, 2, // Right face.
2, 3, 6, 6, 7, 3, // Top face.
3, 7, 4, 4, 3, 0, // Left face.
4, 5, 7, 7, 6, 5)// Rear face.
/** Number of coordinates per vertex in [VERTICES]. */
private const val COORDS_PER_VERTEX = 3
/** Number of values per colors in [COLORS]. */
private const val VALUES_PER_COLOR = 4
/** Shader code for the vertex. */
private const val VERTEX_SHADER_CODE = "uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec4 vColor;" +
"varying vec4 _vColor;" +
"void main() {" +
" _vColor = vColor;" +
" gl_Position = uMVPMatrix * vPosition;" +
"}"
/** Shader code for the fragment. */
private const val FRAGMENT_SHADER_CODE = "precision mediump float;" +
"varying vec4 _vColor;" +
"void main() {" +
" gl_FragColor = _vColor;" +
"}"
/** Loads the provided shader in the program. */
private fun loadShader(type: Int, shaderCode: String): Int {
val shader = GLES20.glCreateShader(type)
GLES20.glShaderSource(shader, shaderCode)
GLES20.glCompileShader(shader)
return shader
}
}
}

100
app/src/main/java/com/google/android/glass/sample/apidemo/opengl/CubeRenderer.kt

@ -0,0 +1,100 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.glass.sample.apidemo.opengl
import com.google.android.glass.timeline.GlRenderer
import android.opengl.GLES20
import android.opengl.Matrix
import android.os.SystemClock
import java.util.concurrent.TimeUnit
import javax.microedition.khronos.egl.EGLConfig
/**
* Renders a 3D OpenGL Cube on a [LiveCard].
*/
class CubeRenderer : GlRenderer {
private val mMVPMatrix: FloatArray = FloatArray(16)
private val mProjectionMatrix: FloatArray = FloatArray(16)
private val mViewMatrix: FloatArray = FloatArray(16)
private val mRotationMatrix: FloatArray = FloatArray(16)
private val mFinalMVPMatrix: FloatArray = FloatArray(16)
private lateinit var mCube: Cube
private var mCubeRotation: Float = 0.toFloat()
private var mLastUpdateMillis: Long = 0
init {
// Set the fixed camera position (View matrix).
Matrix.setLookAtM(mViewMatrix, 0, 0.0f, 0.0f, -4.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f)
}
override fun onSurfaceCreated(config: EGLConfig) {
// Set the background frame color
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
GLES20.glClearDepthf(1.0f)
GLES20.glEnable(GLES20.GL_DEPTH_TEST)
GLES20.glDepthFunc(GLES20.GL_LEQUAL)
mCube = Cube()
}
override fun onSurfaceChanged(width: Int, height: Int) {
val ratio = width.toFloat() / height
GLES20.glViewport(0, 0, width, height)
// This projection matrix is applied to object coordinates in the onDrawFrame() method.
Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1.0f, 1.0f, 3.0f, 7.0f)
// modelView = projection x view
Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0)
}
override fun onDrawFrame() {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT or GLES20.GL_DEPTH_BUFFER_BIT)
// Apply the rotation.
Matrix.setRotateM(mRotationMatrix, 0, mCubeRotation, 1.0f, 1.0f, 1.0f)
// Combine the rotation matrix with the projection and camera view
Matrix.multiplyMM(mFinalMVPMatrix, 0, mMVPMatrix, 0, mRotationMatrix, 0)
// Draw cube.
mCube.draw(mFinalMVPMatrix)
updateCubeRotation()
}
/** Updates the cube rotation. */
private fun updateCubeRotation() {
if (mLastUpdateMillis != 0L) {
val factor = (SystemClock.elapsedRealtime() - mLastUpdateMillis) / FRAME_TIME_MILLIS
mCubeRotation += CUBE_ROTATION_INCREMENT * factor
}
mLastUpdateMillis = SystemClock.elapsedRealtime()
}
companion object {
/** Rotation increment per frame. */
private const val CUBE_ROTATION_INCREMENT = 0.6f
/** The refresh rate, in frames per second. */
private const val REFRESH_RATE_FPS = 60
/** The duration, in milliseconds, of one frame. */
private val FRAME_TIME_MILLIS = (TimeUnit.SECONDS.toMillis(1) / REFRESH_RATE_FPS).toFloat()
}
}

67
app/src/main/java/com/google/android/glass/sample/apidemo/opengl/MenuActivity.kt

@ -0,0 +1,67 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.glass.sample.apidemo.opengl
import com.google.android.glass.sample.apidemo.R
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import java.lang.Runnable
/**
* Activity showing an options menu to stop the [OpenGlService].
*/
class MenuActivity : Activity() {
private val mHandler = Handler()
override fun onAttachedToWindow() {
super.onAttachedToWindow()
openOptionsMenu()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.opengl_livecard, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle item selection.
return when (item.itemId) {
R.id.stop -> {
// Stop the service at the end of the message queue for proper options menu
// animation. This is only needed when starting a new Activity or stopping a Service
// that published a LiveCard.
mHandler.post { stopService(Intent(this@MenuActivity, OpenGlService::class.java)) }
true
}
else -> super.onOptionsItemSelected(item)
}
}
override fun onOptionsMenuClosed(menu: Menu) {
// Nothing else to do, closing the Activity.
finish()
}
}

64
app/src/main/java/com/google/android/glass/sample/apidemo/opengl/OpenGlService.kt

@ -0,0 +1,64 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.glass.sample.apidemo.opengl
import com.google.android.glass.timeline.LiveCard
import com.google.android.glass.timeline.LiveCard.PublishMode
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.os.IBinder
/**
* Creates a [LiveCard] rendering a rotating 3D cube with OpenGL.
*/
class OpenGlService : Service() {
private var mLiveCard: LiveCard? = null
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
if (mLiveCard == null) {
mLiveCard = LiveCard(this, LIVE_CARD_TAG)
mLiveCard!!.setRenderer(CubeRenderer())
mLiveCard!!.setAction(
PendingIntent.getActivity(this, 0, Intent(this, MenuActivity::class.java), 0))
mLiveCard!!.attach(this)
mLiveCard!!.publish(PublishMode.REVEAL)
} else {
mLiveCard!!.navigate()
}
return START_STICKY
}
override fun onDestroy() {
if (mLiveCard != null && mLiveCard!!.isPublished) {
mLiveCard!!.unpublish()
mLiveCard = null
}
super.onDestroy()
}
companion object {
private const val LIVE_CARD_TAG = "opengl"
}
}

176
app/src/main/java/com/google/android/glass/sample/apidemo/slider/SliderActivity.kt

@ -0,0 +1,176 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/