Skip to content

Commit 332e7ea

Browse files
inckieInk
and
Ink
authored
feat: Enterprise Edition support (#5)
* + Enterprise Edition Card sample drop in * * sort out Kotlin configuration * * fix deprecation warning * Rename .java to .kt * * migrate GlassMenuItem to Kotlin * * add exported flags (not really needed for glass Android 8.1, just to keep linter happy) * Rename .java to .kt * * Kotlinize MainLayoutFragment * Rename .java to .kt * * Kotlinize BaseFragment * Rename .java to .kt * * Kotlinize Menu code * Rename .java to .kt * * Kotlinize BaseActivity * Rename .java to .kt * * Kotlinize MainActivity * Rename .java to .kt * * Kotlinize ColumnLayoutFragment * * TODO added * * reorganize code * * replace launcher icon * + isPossiblyTethering utility * + generalize client and host a bit * * get rid of onStopped overload * * bump submodule pointer * + WiFiHost * + required permissions * Rename .java to .kt * + Kotlinize settings and add connection type * + temporary hardcode wifi mode * * todo about missing RPC start failure handling * * very hacky IP sockets client and server drafts * * temporary hacked-in client * * moving mQueue to worker threads * * gradle:8.3.2 * * GPS passthrough test * + basic MapCard * * use Closeables for sockets * * some cleanup * * actually call stop on client * InterruptedException resets interrupted flag, move to boolean and exit command to simplify handling (we can get SocketException first) * * make menu param default null * * change service notification priority to IMPORTANCE_DEFAULT * + switch to material design to get better toggle control * * add Connection type toggle (no nice WiFi icon though) * * bump mobile app gradle deps * * replace old picasso with coil * + ee ProGuard * * temporary move mockGPS code to the `service` and draft MapCard (will not restart mockGPS though) * * developer settings actually work on Glass EE2 * fix crossfade * * Android studio downloaded all icons finally, replace WiFi * *+ local signingConfig * * assemble both debug and release in CI * * bump actions to node 20 versions * * make HostService actually a Service * * fix checkbox * * readme and comments updates --------- Co-authored-by: Ink <i@am.com>
1 parent 341bca9 commit 332e7ea

File tree

76 files changed

+2646
-147
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+2646
-147
lines changed

Diff for: .github/workflows/android_build.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ jobs:
1212
runs-on: ubuntu-latest
1313

1414
steps:
15-
- uses: actions/checkout@v3
15+
- uses: actions/checkout@v4
1616
with:
1717
submodules: 'true'
1818

1919
- name: set up JDK 17
20-
uses: actions/setup-java@v3
20+
uses: actions/setup-java@v4
2121
with:
2222
java-version: '17'
2323
distribution: 'temurin'
@@ -29,4 +29,4 @@ jobs:
2929
run: chmod +x gradlew
3030

3131
- name: Build with Gradle
32-
run: ./gradlew assembleDebug
32+
run: ./gradlew assemble

Diff for: README.md

+37-8
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,49 @@
11
# AnotherGlass for Google Glass
22

3-
Companion application to handle **Google Glass Explorer Edition** communication with a phone without official My Glass application and related Google Services.
3+
![Logo](mobile/src/main/ic_launcher-playstore.png "Logo")
4+
5+
Companion application to handle **Google Glass Explorer Edition** and **Google Glass Enterprise Edition** communication with a phone without the official "My Glass" application and related Google Services.
46

57
Currently, the application can:
68
* pass GPS data from the phone to the Glass
7-
* forwarding ongoing and one-shot notifications to the Glass
8-
* pass WiFi network information (SSID and password) from the phone to the Glass
9+
* forwarding ongoing and one-shot notifications to the Glass (Explorer Edition only)
10+
* pass WiFi network information (SSID and password) from the phone to the Glass (Explorer Edition only)
911

1012
## Building
1113

1214
Project consist of 3 modules:
13-
* **glass** - Google Glass application, containing Client Service
15+
* **glass** - Google Glass Explorer Edition application, containing Client Service
16+
* **glass-ee** - Google Glass Enterprise Edition application, containing Client Service
1417
* **mobile** - companion application for mobile device, containing Host Service
1518
* **shared** - a shared module with shared classes and constants
19+
* **shared-glass** - a shared module between Glass apps
1620

1721
## Running
22+
23+
**Google Glass Explorer Edition**
24+
25+
Uses Bluetooth to connect to the phone. WiFi tethering is not supported yet.
26+
1827
1. Pair the Glass with the phone.
19-
2. Install both apps
20-
3. Toggle service switch on the phone application to start Host Service
21-
4. On Glass, use a 'Sign in' menu option ('Help me sign in' voice command) to start Client Service
28+
2. Install both apps.
29+
3. Select Bluetooth connection mode in the mobile app.
30+
4. Toggle service switch on the phone application to start Host Service.
31+
5. On the Glass, use a 'Sign in' menu option ('Help me sign in' voice command) to start Client Service.
32+
33+
**Google Glass Enterprise Edition**
34+
35+
Uses WiFi to connect to the phone. Bluetooth is not supported (it has issues connecting from UI on latest firmware, and can only be connected from hidden Applications settings on my device, but disconnects often).
36+
37+
1. Setup and start WiFi hotspot on the phone.
38+
2. Connect the Glass to the phone's WiFi network.
39+
3. Install both apps.
40+
4. Select WiFi connection mode in the mobile app.
41+
5. Toggle service switch on the phone application to start Host Service. Accept the permissions requests.
42+
6. Run AnotherGlass app on the Glass device. Accept the permission requests.
43+
44+
Use swipe up or two fingers swipe down gestures to stop the service.
45+
46+
To enable GPS location passthrough on the Glass you will need to give the app MOCK_LOCATION permission. Run ADB command `adb shell appops set com.damn.anotherglass.glass.ee android:mock_location allow`, or tap on the Map card to open Developer settings and set AnotherGlass as GPS mocking application. Restart the service after the change.
2247

2348
## Details
2449

@@ -28,9 +53,13 @@ Uses Java object stream to send data to Google Glass, since I don't want to mess
2853

2954
## AnotherGlass Plans
3055

31-
* Add version for Google Glass Enterprise Edition 2 (Android 8.1). Will require a separate module, since it lacks stock Glass APIs like LiveCards, and also needs to handle permissions and so on. Latest firmware has known issues with Bluetooth, so I will need to add WiFi tethering support mode.
3256
* Rewrite the connections loops, so listening thread will be waiting for the incoming messages, and sending will happen in a separate thread (how I have peek/sleep cycle typical for desktop applications).
3357
* Handle Bluetooth reconnects (Glass sometimes loses the Bluetooth connection and immediately reconnects, but I stop the service for now).
58+
* Improve initial connect experience on the Glass Enterprise Edition:
59+
* add service start/stop menu
60+
* move GPS permissions handling to the Map card and make the permissions optional to start the service
61+
* handle permissions and MockGPS status changes without restarting the service
62+
* Add WiFi connection mode to the Glass Explorer Edition, and Bluetooth to Glass Enterprise Edition apps.
3463
* Add one time notification stack activity (easy, but lazy).
3564
* Add notifications filter options and better display.
3665
* Try to handle notifications action buttons on the Glass.

Diff for: build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

33
buildscript {
4-
ext.kotlin_version = '1.7.20'
4+
ext.kotlin_version = '1.9.23'
55

66
repositories {
77
google()
88
mavenCentral()
99
}
1010
dependencies {
11-
classpath 'com.android.tools.build:gradle:8.3.1'
11+
classpath 'com.android.tools.build:gradle:8.3.2'
1212
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1313

1414

Diff for: glass-ee/.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/bin
2+
/build

Diff for: glass-ee/build.gradle

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2019 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
apply plugin: 'com.android.application'
18+
apply plugin: 'org.jetbrains.kotlin.android'
19+
20+
apply from: file('../gradle/signing.gradle')
21+
22+
android {
23+
defaultConfig {
24+
compileSdk 34
25+
applicationId "com.damn.anotherglass.glass.ee"
26+
minSdkVersion 27
27+
//noinspection ExpiredTargetSdkVersion
28+
targetSdkVersion 28
29+
versionCode 1
30+
versionName "1.0"
31+
}
32+
33+
signingConfigs {
34+
if (null != project.ext.signingConfig) {
35+
config project.ext.signingConfig
36+
}
37+
}
38+
39+
buildTypes {
40+
release {
41+
minifyEnabled true
42+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
43+
signingConfig null != project.ext.signingConfig ? signingConfigs.config : signingConfigs.debug
44+
}
45+
debug {
46+
signingConfig null != project.ext.signingConfig ? signingConfigs.config : signingConfigs.debug
47+
}
48+
}
49+
50+
buildFeatures {
51+
dataBinding true
52+
viewBinding true
53+
}
54+
55+
compileOptions {
56+
sourceCompatibility JavaVersion.VERSION_17
57+
targetCompatibility JavaVersion.VERSION_17
58+
}
59+
kotlinOptions {
60+
jvmTarget = JavaVersion.VERSION_17.toString()
61+
}
62+
namespace 'com.damn.anotherglass.glass.ee.host'
63+
}
64+
65+
dependencies {
66+
implementation project(':shared')
67+
implementation project(':glass-shared')
68+
implementation project(':glass-ee-gestures')
69+
implementation 'androidx.recyclerview:recyclerview:1.3.2'
70+
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
71+
implementation 'com.google.android.material:material:1.11.0'
72+
implementation 'androidx.core:core-ktx:1.12.0'
73+
74+
implementation 'io.coil-kt:coil:2.6.0'
75+
}

Diff for: glass-ee/proguard-rules.pro

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
22+
-keepnames class * implements java.io.Serializable
23+
-keepclassmembers class * implements java.io.Serializable { *; }

Diff for: glass-ee/src/main/AndroidManifest.xml

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?xml version="1.0" encoding="utf-8"?><!--
2+
Copyright 2019 Google LLC
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
-->
16+
17+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
18+
xmlns:tools="http://schemas.android.com/tools">
19+
20+
<!-- Service -->
21+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
22+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
23+
<!-- WiFi client -->
24+
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
25+
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
26+
<uses-permission android:name="android.permission.INTERNET" />
27+
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
28+
<!-- GPS extension -->
29+
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
30+
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
31+
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
32+
<uses-permission
33+
android:name="android.permission.ACCESS_MOCK_LOCATION"
34+
tools:ignore="MockLocation,ProtectedPermissions" />
35+
36+
<application
37+
android:allowBackup="true"
38+
android:icon="@mipmap/ic_launcher"
39+
android:label="@string/app_name"
40+
android:roundIcon="@mipmap/ic_launcher"
41+
android:supportsRtl="true"
42+
android:theme="@style/AppTheme">
43+
<!--
44+
Changes Glass touchpad response from the following key strokes:
45+
- Enter
46+
- Tab
47+
- Shift + Tab
48+
- Back button
49+
- Home button
50+
- Arrows
51+
to the motion events, enabling this app to use the touch gestures.
52+
-->
53+
<meta-data
54+
android:name="com.google.android.glass.TouchEnabledApplication"
55+
android:value="true" />
56+
57+
<activity
58+
android:name=".ui.MainActivity"
59+
android:exported="true">
60+
<intent-filter>
61+
<action android:name="android.intent.action.MAIN" />
62+
63+
<category android:name="android.intent.category.LAUNCHER" />
64+
<category android:name="com.google.android.glass.category.DIRECTORY" />
65+
</intent-filter>
66+
</activity>
67+
<activity
68+
android:name=".ui.menu.MenuActivity"
69+
android:exported="false"
70+
android:theme="@style/MenuTheme">
71+
<intent-filter>
72+
<!-- must be VIEW or PICK -->
73+
<action android:name="android.intent.action.MAIN" />
74+
75+
<category android:name="android.intent.category.DEFAULT" />
76+
</intent-filter>
77+
</activity>
78+
<service
79+
android:name=".core.HostService"
80+
android:enabled="true"
81+
android:exported="true" />
82+
</application>
83+
84+
</manifest>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.damn.anotherglass.glass.ee.host
2+
3+
import android.Manifest
4+
5+
// Permissions actual for Android 8.1
6+
val gpsPermissions = arrayOf(
7+
Manifest.permission.ACCESS_FINE_LOCATION,
8+
Manifest.permission.ACCESS_COARSE_LOCATION
9+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.damn.anotherglass.glass.ee.host.core
2+
3+
import android.content.Context
4+
import android.net.wifi.WifiManager
5+
import android.text.format.Formatter
6+
7+
object ConnectionUtils {
8+
fun isPossiblyTethering(ip: String): Boolean {
9+
// Check is IP address is in the range of possible tethering addresses.
10+
// default tethering IP ranges addresses are
11+
// - USB is 192.168.42.1 and 255.255.255.0
12+
// - Wifi is 192.168.43.1 and 255.255.255.0
13+
// - BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
14+
// and gateway 192.168.42.129,
15+
// but different devices can have different settings: 192.168.6.0, 192.168.200.0, etc.
16+
// as defined in the device config.xml config_dhcp_range/config_tether_dhcp_range values
17+
// or configurable in device settings.
18+
// We just check for 192.168. mask, and that bluetooth is not connected in the calling code
19+
return ip.startsWith("192.168.")
20+
}
21+
22+
// todo: replace deprecated API, move isPossiblyTethering up
23+
fun getHostIPAddress(context: Context): String? {
24+
val wf = context.getSystemService(Context.WIFI_SERVICE) as WifiManager
25+
val dhcpInfo = wf.dhcpInfo ?: return null
26+
val tmp = dhcpInfo.gateway
27+
val ip = Formatter.formatIpAddress(tmp)
28+
return if(isPossiblyTethering(ip)) ip else null
29+
}
30+
}

0 commit comments

Comments
 (0)