xrt/android: Actually start using dependency injection in Java/Kotlin code.

This commit is contained in:
Ryan Pavlik 2020-11-13 15:02:07 -06:00 committed by Lubosz Sarnecki
parent 3c3d628f0c
commit 2fe699d7c1
16 changed files with 372 additions and 3 deletions

View file

@ -4,6 +4,7 @@
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'dagger.hilt.android.plugin'
}
android {
@ -39,4 +40,9 @@ dependencies {
implementation "androidx.annotation:annotation:$androidxAnnotationVersion"
implementation "androidx.core:core-ktx:$androidxCoreVersion"
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
// for Hilt dependency injection
implementation "com.google.dagger:hilt-android:$hiltVersion"
// Only a Java file has annotations right now, so we don't yet need kapt
annotationProcessor "com.google.dagger:hilt-compiler:$hiltVersion"
}

View file

@ -27,7 +27,10 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Calendar;
import dagger.hilt.android.AndroidEntryPoint;
@Keep
@AndroidEntryPoint
public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, SurfaceHolder.Callback2 {
private static final String TAG = "MonadoView";
@SuppressWarnings("deprecation")

View file

@ -0,0 +1,29 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Interface for target-specific branding things on Android.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
* @ingroup aux_android
*/
package org.freedesktop.monado.auxiliary
import android.graphics.drawable.Drawable
/**
* Branding-related UI stuff. This interface must be provided by any Android "XRT Target".
*
* Intended for use in dependency injection.
*/
interface NameAndLogoProvider {
/**
* Gets a localized runtime name string for the runtime/Monado-incorporating target.
*/
fun getLocalizedRuntimeName(): CharSequence
/**
* Gets a drawable for use in the about activity and elsewhere, for the runtime/Monado-incorporating target.
*/
fun getLogoDrawable(): Drawable?
}

View file

@ -0,0 +1,39 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Interface for target-specific UI-related things on Android.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
* @ingroup aux_android
*/
package org.freedesktop.monado.auxiliary
import android.app.PendingIntent
import android.content.Context
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
/**
* Non-branding-related UI stuff. This interface must be provided by any Android "XRT Target".
*
* Intended for use in dependency injection.
*/
interface UiProvider {
/**
* Gets a drawable for use in a notification, for the runtime/Monado-incorporating target.
*
* Optional - you can return null.
*/
fun getNotificationIcon(): Icon? = null
/**
* Make a {@code PendingIntent} to launch an "About" activity for the runtime/target.
*/
fun makeAboutActivityPendingIntent(): PendingIntent
/**
* Make a {@code PendingIntent} to launch a configuration activity, if provided by the target.
*/
fun makeConfigureActivityPendingIntent(): PendingIntent? = null
}

View file

@ -4,6 +4,9 @@
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
}
android {
@ -49,4 +52,8 @@ dependencies {
implementation "androidx.annotation:annotation:$androidxAnnotationVersion"
implementation "androidx.core:core-ktx:$androidxCoreVersion"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
// for Hilt dependency injection
api "com.google.dagger:hilt-android:$hiltVersion"
kapt "com.google.dagger:hilt-compiler:$hiltVersion"
}

View file

@ -157,7 +157,7 @@ public class Client implements ServiceConnection {
return false;
}
intent = new Intent(BuildConfig.SERVICE_ACTION)
Intent intent = new Intent(BuildConfig.SERVICE_ACTION)
.setPackage(packageName);
context.startForegroundService(intent);

View file

@ -11,16 +11,18 @@ package org.freedesktop.monado.ipc
import android.app.Service
import android.content.Intent
import android.os.IBinder
import dagger.hilt.android.AndroidEntryPoint
/**
* Minimal implementation of a Service.
*
* This is needed so that the APK can expose the binder service implemented in MonadoImpl.
*/
@AndroidEntryPoint
class MonadoService : Service() {
val monado: MonadoImpl = MonadoImpl()
override fun onBind(intent: Intent): IBinder? {
return monado;
return monado
}
}

View file

@ -6,6 +6,13 @@ import groovy.xml.XmlUtil
plugins {
id 'com.android.application'
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'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
@ -178,4 +185,9 @@ dependencies {
implementation "androidx.cardview:cardview:1.*.*"
implementation "androidx.recyclerview:recyclerview:1.1.*"
// for Hilt dependency injection
implementation "com.google.dagger:hilt-android:$hiltVersion"
kapt "com.google.dagger:hilt-compiler:$hiltVersion"
}

View file

@ -39,6 +39,7 @@
android:required="false" />
<application
android:name=".MonadoOpenXrApplication"
android:allowBackup="true"
android:extractNativeLibs="true"
android:icon="@drawable/ic_monado_logo"

View file

@ -19,6 +19,9 @@ import androidx.fragment.app.FragmentTransaction;
import com.mikepenz.aboutlibraries.LibsBuilder;
import dagger.hilt.android.AndroidEntryPoint;
@AndroidEntryPoint
public class AboutActivity extends AppCompatActivity {
@Override

View file

@ -0,0 +1,33 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Module that binds all the dependencies we inject with Hilt.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
package org.freedesktop.monado.openxr_runtime
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ApplicationComponent
import org.freedesktop.monado.auxiliary.NameAndLogoProvider
import org.freedesktop.monado.auxiliary.UiProvider
/**
* This is implemented by Hilt/Dagger to do dependency injection.
*
* Each declaration essentially signals to Hilt/Dagger what subclass/implementation of a
* base/interface to use for each thing it must inject.
*/
@Module
@InstallIn(ApplicationComponent::class)
abstract class MonadoOpenXrAndroidModule {
@Binds
abstract fun bindUiProvider(uiProvider: MonadoOpenXrUiProvider): UiProvider
@Binds
abstract fun bindNameAndLogo(monadoOpenXrBrandingUiProvider: MonadoOpenXrBrandingUiProvider): NameAndLogoProvider
}

View file

@ -0,0 +1,19 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Simple Application subclass.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
package org.freedesktop.monado.openxr_runtime;
import android.app.Application;
import dagger.hilt.android.HiltAndroidApp;
/**
* Subclass required for Hilt usage.
*/
@HiltAndroidApp
public class MonadoOpenXrApplication extends Application {
}

View file

@ -0,0 +1,28 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Simple implementation of NameAndLogoProvider.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
package org.freedesktop.monado.openxr_runtime
import android.content.Context
import android.graphics.drawable.Drawable
import androidx.core.content.ContextCompat
import dagger.hilt.android.qualifiers.ApplicationContext
import org.freedesktop.monado.auxiliary.NameAndLogoProvider
import javax.inject.Inject
class MonadoOpenXrBrandingUiProvider @Inject constructor(@ApplicationContext val context: Context) : NameAndLogoProvider {
/**
* Gets a localized runtime name string for the runtime/Monado-incorporating target.
*/
override fun getLocalizedRuntimeName(): CharSequence = context.packageManager.getApplicationLabel(context.applicationInfo)
/**
* Gets a drawable for use in the about activity and elsewhere, for the runtime/Monado-incorporating target.
*/
override fun getLogoDrawable(): Drawable? = ContextCompat.getDrawable(context, R.drawable.ic_monado_logo)
}

View file

@ -0,0 +1,41 @@
// Copyright 2020, Collabora, Ltd.
// SPDX-License-Identifier: BSL-1.0
/*!
* @file
* @brief Simple implementation of UiProvider.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
*/
package org.freedesktop.monado.openxr_runtime
import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Icon
import dagger.hilt.android.qualifiers.ApplicationContext
import org.freedesktop.monado.auxiliary.UiProvider
import javax.inject.Inject
class MonadoOpenXrUiProvider @Inject constructor(@ApplicationContext val context: Context) : UiProvider {
/**
* Gets a drawable for use in a notification, for the runtime/Monado-incorporating target.
*/
override fun getNotificationIcon(): Icon? =
Icon.createWithResource(context, R.drawable.ic_notif_xr_letters_custom)
/**
* Make a {@code PendingIntent} to launch an "About" activity for the runtime/target.
*/
override fun makeAboutActivityPendingIntent(): PendingIntent =
PendingIntent.getActivity(context,
0,
Intent.makeMainActivity(
ComponentName.createRelative(context,
AboutActivity::class.qualifiedName!!)),
0
)
}

View file

@ -32,14 +32,22 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import org.freedesktop.monado.auxiliary.NameAndLogoProvider;
import org.freedesktop.monado.auxiliary.UiProvider;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
/**
* A Fragment for displaying/affecting VR Listener status.
*/
@AndroidEntryPoint
public class VrModeStatus extends Fragment {
public static final int STATUS_UNKNOWN = -2;
public static final int STATUS_DISABLED = 0;
@ -47,6 +55,13 @@ public class VrModeStatus extends Fragment {
public static final int STATUS_NOT_AVAIL = -1;
private static final String TAG = "MonadoVrModeStatus";
private static final String ARG_STATUS = "status";
@Inject
UiProvider uiProvider;
@Inject
NameAndLogoProvider nameAndLogoProvider;
private @Status
int status_ = STATUS_UNKNOWN;
@ -164,7 +179,9 @@ public class VrModeStatus extends Fragment {
button.setVisibility(View.VISIBLE);
break;
case STATUS_NOT_AVAIL:
textEnabledDisabled.setText(res.getString(R.string.vr_mode_not_avail, res.getString(R.string.app_name)));
textEnabledDisabled.setText(
res.getString(R.string.vr_mode_not_avail,
nameAndLogoProvider.getLocalizedRuntimeName()));
textEnabledDisabled.setVisibility(View.VISIBLE);
button.setVisibility(View.GONE);
break;

View file

@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!--
Copyright 2020, Collabora, Ltd.
SPDX-License-Identifier: BSL-1.0
-->
<!--suppress ALL -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="48.0px"
height="48.0px"
viewBox="0 0 48.0 48.0"
version="1.1"
id="SVGRoot"
sodipodi:docname="XR-letters-custom.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<title
id="title1424">XR Notification Icon</title>
<defs
id="defs833" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.2"
inkscape:cx="5.3955796"
inkscape:cy="14.492416"
inkscape:document-units="px"
inkscape:current-layer="layer1"
inkscape:document-rotation="0"
showgrid="true"
inkscape:window-width="2560"
inkscape:window-height="1377"
inkscape:window-x="2552"
inkscape:window-y="-8"
inkscape:window-maximized="1"
showguides="true"
inkscape:guide-bbox="true">
<inkscape:grid
type="xygrid"
id="grid1403" />
<sodipodi:guide
position="24,24"
orientation="0,-1"
id="guide1427" />
<sodipodi:guide
position="24,27"
orientation="0,-1"
id="guide1429" />
<sodipodi:guide
position="24,21"
orientation="0,-1"
id="guide1431" />
</sodipodi:namedview>
<metadata
id="metadata836">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>XR Notification Icon</dc:title>
<cc:license
rdf:resource="https://www.boost.org/LICENSE_1_0.txt" />
<dc:date>2020</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Collabora, Ltd.</dc:title>
</cc:Agent>
</dc:creator>
<dc:publisher>
<cc:Agent>
<dc:title>Collabora, Ltd.</dc:title>
</cc:Agent>
</dc:publisher>
<dc:contributor>
<cc:Agent>
<dc:title>Ryan Pavlik &lt;ryan.pavlik@collabora.com&gt;</dc:title>
</cc:Agent>
</dc:contributor>
<dc:rights>
<cc:Agent>
<dc:title>Copyright 2020</dc:title>
</cc:Agent>
</dc:rights>
</cc:Work>
</rdf:RDF>
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
d="m 27,6 v 38 l 5,-0.01563 V 25 c 0,0 8,0 8,4 v 15 h 5 V 29 c 0,-3 -4,-5 -6,-5 2,0 6,0 6,-3 V 6 C 45,3 27,3 27,6 Z m 5,1 c 0,-1 8,-1 8,0 v 14 c 0,2 -8,2 -8,2 z"
id="path1439"
sodipodi:nodetypes="ccccccccccccccccc" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000;stop-opacity:1"
d="m 3,4 v 17 c 0,4 14,2 14,6 v 17 h 5 V 27 C 22,23 8,25 8,21 V 4 Z"
id="path1443"
sodipodi:nodetypes="ccccccccc" />
<use
x="0"
y="0"
xlink:href="#path1443"
id="use1445"
transform="matrix(-1,0,0,1,25,0)"
width="100%"
height="100%"
style="opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB