t/oxr_android: Split android UI that is not target-specific to a separate common target.

This commit is contained in:
Ryan Pavlik 2020-11-13 14:30:20 -06:00 committed by Lubosz Sarnecki
parent 2fe699d7c1
commit 70542fbb3b
21 changed files with 318 additions and 114 deletions

View file

@ -5,4 +5,5 @@ rootProject.name = 'monado'
include ':src:xrt:auxiliary:android'
include ':src:xrt:ipc:android'
include ':src:xrt:targets:android_common'
include ':src:xrt:targets:openxr_android'

View file

@ -0,0 +1,56 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
plugins {
id 'com.android.library'
id 'kotlin-android'
// Hilt dependency injection
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
// SVG files in the "raw" resource directory will be transformed into vector drawables of the same name.
id 'com.quittle.svg-2-android-vector'
}
android {
compileSdkVersion project.sharedTargetSdk
buildToolsVersion '30.0.2'
defaultConfig {
minSdkVersion project.sharedMinSdk
targetSdkVersion project.sharedTargetSdk
}
buildTypes {
release {
minifyEnabled false
// Gradle plugin produces proguard-android-optimize.txt from @Keep annotations
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
lintOptions {
fatal 'StopShip'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
packagingOptions {
exclude("META-INF/*.kotlin_module")
}
}
dependencies {
implementation project(':src:xrt:auxiliary:android')
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
implementation "androidx.constraintlayout:constraintlayout:$androidxConstraintLayoutVersion"
implementation "com.google.android.material:material:$materialVersion"
// for Hilt dependency injection
implementation "com.google.dagger:hilt-android:$hiltVersion"
kapt "com.google.dagger:hilt-compiler:$hiltVersion"
}

View file

@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.freedesktop.monado.android_common">
<!--
Copyright 2020, Collabora, Ltd.
SPDX-License-Identifier: BSL-1.0
-->
<!-- We may try to use OpenGL|ES 3.0 -->
<uses-feature
android:glEsVersion="0x00030002"
android:required="true" />
<!-- This is for Android's VR mode. -->
<uses-feature
android:name="android.software.vr.mode"
android:required="false" />
<!-- This feature is available on only Daydream-ready devices: may use it if it's there. -->
<uses-feature
android:name="android.hardware.vr.high_performance"
android:required="false" />
<!-- Can handle both 3-DOF and 6-DOF head tracking. -->
<uses-feature
android:name="android.hardware.vr.headtracking"
android:required="false"
android:version="1" />
<!-- for sensor access -->
<uses-feature
android:name="android.hardware.sensor.accelerometer"
android:required="false" />
<uses-feature
android:name="android.hardware.sensor.gyroscope"
android:required="false" />
<uses-feature
android:name="android.hardware.sensor.hifi_sensors"
android:required="false" />
<application
android:allowBackup="true"
android:extractNativeLibs="true"
android:icon="@drawable/ic_monado_logo"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- Main "about" activity -->
<activity android:name=".AboutActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -0,0 +1,88 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Simple main activity for Android.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
package org.freedesktop.monado.android_common;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import org.freedesktop.monado.auxiliary.NameAndLogoProvider;
import org.freedesktop.monado.auxiliary.UiProvider;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
@AndroidEntryPoint
public class AboutActivity extends AppCompatActivity {
@Inject
NoticeFragmentProvider noticeFragmentProvider;
@Inject
UiProvider uiProvider;
@Inject
NameAndLogoProvider nameAndLogoProvider;
private boolean isInProcessBuild() {
try {
getClassLoader().loadClass("org/freedesktop/monado/ipc/Client");
return false;
} catch (ClassNotFoundException e) {
// ok, we're in-process.
}
return true;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
// Default to dark mode universally?
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
// Make our Monado link clickable
((TextView) findViewById(R.id.textPowered)).setMovementMethod(LinkMovementMethod.getInstance());
// Branding from the branding provider
((TextView) findViewById(R.id.textName)).setText(nameAndLogoProvider.getLocalizedRuntimeName());
((ImageView) findViewById(R.id.imageView)).setImageDrawable(nameAndLogoProvider.getLogoDrawable());
if (!isInProcessBuild()) {
ShutdownProcess.Companion.setupRuntimeShutdownButton(this);
}
// Start doing fragments
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
@VrModeStatus.Status
int status = VrModeStatus.detectStatus(this,
getApplicationContext().getApplicationInfo().packageName);
VrModeStatus statusFrag = VrModeStatus.newInstance(status);
fragmentTransaction.add(R.id.statusFrame, statusFrag, null);
if (noticeFragmentProvider != null) {
Fragment noticeFragment = noticeFragmentProvider.makeNoticeFragment();
fragmentTransaction.add(R.id.aboutFrame, noticeFragment, null);
}
fragmentTransaction.commit();
}
}

View file

@ -6,7 +6,7 @@
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
package org.freedesktop.monado.openxr_runtime
package org.freedesktop.monado.android_common
import android.content.ComponentName
import android.os.Build

View file

@ -0,0 +1,23 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Interface for target-specific .
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
package org.freedesktop.monado.android_common
import androidx.fragment.app.Fragment
/**
* Provides a fragment with open-source license notices and attribution that we can put in our
* "About" activity.
*
* Provided by dependency injection from the final target: e.g. AboutLibraries must come from there
* to be sure to collect all dependencies to credit.
*/
interface NoticeFragmentProvider {
fun makeNoticeFragment(): Fragment
}

View file

@ -0,0 +1,29 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Helper providing a shutdown button in the about activity.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
package org.freedesktop.monado.android_common
import android.os.Process
import android.view.View
import android.widget.Button
class ShutdownProcess {
companion object {
/**
* Show and handle the shutdown runtime button.
*/
fun setupRuntimeShutdownButton(activity: AboutActivity) {
val button =
activity.findViewById<Button>(R.id.shutdown)
button.visibility = View.VISIBLE
button.setOnClickListener {
Process.killProcess(Process.myPid())
}
}
}
}

View file

@ -6,7 +6,7 @@
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
package org.freedesktop.monado.openxr_runtime;
package org.freedesktop.monado.android_common;
import android.annotation.SuppressLint;
import android.content.ComponentName;

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2020, Collabora, Ltd.
SPDX-License-Identifier: BSL-1.0
-->
@ -15,7 +14,7 @@
android:layout_width="@android:dimen/thumbnail_width"
android:layout_height="@android:dimen/thumbnail_height"
android:layout_marginTop="8dp"
android:contentDescription="@string/monado_logo"
android:contentDescription="@string/logo_text"
android:scaleType="fitCenter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
@ -24,11 +23,11 @@
app:srcCompat="@drawable/ic_monado_logo" />
<TextView
android:id="@+id/textView"
android:id="@+id/textName"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:text="@string/app_name"
android:text="name"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
@ -55,7 +54,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
app:layout_constraintTop_toBottomOf="@+id/textName" />
<Button
android:id="@+id/shutdown"
@ -75,7 +74,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="imageView,textPowered,textView,versionView,shutdown"
app:constraint_referenced_ids="imageView,textPowered,textName,versionView,shutdown"
tools:layout_editor_absoluteY="252dp" />
<FrameLayout

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?><!--
Copyright 2020, Collabora, Ltd.
SPDX-License-Identifier: BSL-1.0
-->
<resources>
<color name="colorPrimary">#2196F3</color>
<color name="colorPrimaryDark">#3F51B5</color>
<color name="colorAccent">#FF9800</color>
</resources>

View file

@ -0,0 +1,14 @@
<resources>
<!--
Copyright 2020, Collabora, Ltd.
SPDX-License-Identifier: BSL-1.0
-->
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

View file

@ -10,6 +10,6 @@
<string name="vr_mode_disabled">Built-in Android VR Mode features are available on this device, but are <b>not enabled</b> for this runtime. You can enable them below.</string>
<string name="vr_mode_not_avail">No built-in Android VR Mode features are available on this device, but %1$s does not require them.</string>
<string name="launch_settings">Open Android VR Settings</string>
<string name="monado_logo">Monado logo</string>
<string name="logo_text">Logo</string>
</resources>

View file

@ -1,12 +1,12 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
import groovy.xml.XmlUtil
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'com.mikepenz.aboutlibraries.plugin'
// Hilt dependency injection
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
@ -14,9 +14,6 @@ plugins {
// SVG files in the "raw" resource directory will be transformed into vector drawables of the same name.
id 'com.quittle.svg-2-android-vector'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'com.mikepenz.aboutlibraries.plugin'
androidGitVersion {
tagPattern(/^v[0-9]+.*/)
@ -174,6 +171,7 @@ aboutLibraries {
dependencies {
outOfProcessImplementation project(':src:xrt:ipc:android')
implementation project(':src:xrt:auxiliary:android')
implementation project(':src:xrt:targets:android_common')
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
implementation "androidx.constraintlayout:constraintlayout:$androidxConstraintLayoutVersion"

View file

@ -46,17 +46,10 @@
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- Main "about" activity -->
<activity android:name=".AboutActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- VR Listener service, for interop with Android VR mode. -->
<service
android:name=".MonadoVrListener"
android:name="org.freedesktop.monado.android_common.MonadoVrListener"
android:icon="@drawable/ic_monado_logo"
android:label="@string/app_name"
android:permission="android.permission.BIND_VR_LISTENER_SERVICE">

View file

@ -1,67 +0,0 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Simple main activity for Android.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
package org.freedesktop.monado.openxr_runtime;
import android.os.Bundle;
import android.text.method.LinkMovementMethod;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.mikepenz.aboutlibraries.LibsBuilder;
import dagger.hilt.android.AndroidEntryPoint;
@AndroidEntryPoint
public class AboutActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
// Make our Monado link clickable
((TextView) findViewById(R.id.textPowered)).setMovementMethod(LinkMovementMethod.getInstance());
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
@VrModeStatus.Status
int status = VrModeStatus.detectStatus(this, BuildConfig.APPLICATION_ID);
VrModeStatus statusFrag = VrModeStatus.newInstance(status);
fragmentTransaction.add(R.id.statusFrame, statusFrag, null);
boolean inProcess = true;
try {
Class clientClass = getClassLoader().loadClass("org/freedesktop/monado/ipc/Client");
inProcess = false;
} catch (ClassNotFoundException e) {
// ok, we're in-process.
}
if (!inProcess) {
new ShutdownProcess().adjustLayout(this);
}
Fragment libsFragment = (new LibsBuilder())
.withFields(R.string.class.getFields())
// We do this ourselves bigger
.withAboutIconShown(false)
// Let the fragment show our version
.withAboutVersionShown(true)
// Not sure why you'd do this without license info
.withLicenseShown(true)
.supportFragment();
fragmentTransaction.add(R.id.aboutFrame, libsFragment, null);
fragmentTransaction.commit();
}
}

View file

@ -0,0 +1,24 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Provides a "Notice" fragment using AboutLibraries.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
package org.freedesktop.monado.openxr_runtime
import androidx.fragment.app.Fragment
import com.mikepenz.aboutlibraries.LibsBuilder
import org.freedesktop.monado.android_common.NoticeFragmentProvider
import javax.inject.Inject
class AboutLibrariesNoticeFragmentProvider @Inject constructor() : NoticeFragmentProvider {
override fun makeNoticeFragment(): Fragment = LibsBuilder()
.withFields(R.string::class.java.fields) // We do this ourselves bigger
.withAboutIconShown(false) // Let the fragment show our version
.withAboutVersionShown(true) // Not sure why you'd do this without license info
.withLicenseShown(true)
.supportFragment()
}

View file

@ -12,6 +12,7 @@ import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import org.freedesktop.monado.android_common.NoticeFragmentProvider
import org.freedesktop.monado.auxiliary.NameAndLogoProvider
import org.freedesktop.monado.auxiliary.UiProvider
@ -30,4 +31,6 @@ abstract class MonadoOpenXrAndroidModule {
@Binds
abstract fun bindNameAndLogo(monadoOpenXrBrandingUiProvider: MonadoOpenXrBrandingUiProvider): NameAndLogoProvider
@Binds
abstract fun bindNoticeFragment(noticeFragmentProvider: AboutLibrariesNoticeFragmentProvider): NoticeFragmentProvider
}

View file

@ -14,6 +14,7 @@ import android.content.Context
import android.content.Intent
import android.graphics.drawable.Icon
import dagger.hilt.android.qualifiers.ApplicationContext
import org.freedesktop.monado.android_common.AboutActivity
import org.freedesktop.monado.auxiliary.UiProvider
import javax.inject.Inject

View file

@ -1,24 +0,0 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Helper providing a shutdown button in the about activity.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
package org.freedesktop.monado.openxr_runtime
import android.os.Process
import android.view.View
import android.widget.Button
class ShutdownProcess {
fun adjustLayout(activity: AboutActivity) {
val button =
activity.findViewById<Button>(R.id.shutdown)
button.visibility = View.VISIBLE
button.setOnClickListener {
Process.killProcess(Process.myPid())
}
}
}