forked from flutter/packages
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[camerax] Add
LifecycleOwner
Proxy (flutter#3837)
Adds proxy implementation of `LifecycleOwner` for `Activity`s this plugin may be bound to. Heavily inspired by [`google_maps_flutter_android`](https://github.com/flutter/packages/blob/main/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapsPlugin.java#L121). Fixes flutter/flutter#125695.
- Loading branch information
Showing
6 changed files
with
321 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
90 changes: 90 additions & 0 deletions
90
...roid_camerax/android/src/main/java/io/flutter/plugins/camerax/ProxyLifecycleProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
package io.flutter.plugins.camerax; | ||
|
||
import android.app.Activity; | ||
import android.app.Application.ActivityLifecycleCallbacks; | ||
import android.os.Bundle; | ||
import androidx.annotation.NonNull; | ||
import androidx.annotation.VisibleForTesting; | ||
import androidx.lifecycle.Lifecycle; | ||
import androidx.lifecycle.Lifecycle.Event; | ||
import androidx.lifecycle.LifecycleOwner; | ||
import androidx.lifecycle.LifecycleRegistry; | ||
|
||
/** | ||
* This class provides a custom {@link LifecycleOwner} for the activity driven by {@link | ||
* ActivityLifecycleCallbacks}. | ||
* | ||
* <p>This is used in the case where a direct {@link LifecycleOwner} is not available. | ||
*/ | ||
public class ProxyLifecycleProvider implements ActivityLifecycleCallbacks, LifecycleOwner { | ||
|
||
@VisibleForTesting @NonNull public LifecycleRegistry lifecycle = new LifecycleRegistry(this); | ||
private final int registrarActivityHashCode; | ||
|
||
ProxyLifecycleProvider(@NonNull Activity activity) { | ||
this.registrarActivityHashCode = activity.hashCode(); | ||
activity.getApplication().registerActivityLifecycleCallbacks(this); | ||
} | ||
|
||
@Override | ||
public void onActivityCreated(@NonNull Activity activity, @NonNull Bundle savedInstanceState) { | ||
if (activity.hashCode() != registrarActivityHashCode) { | ||
return; | ||
} | ||
lifecycle.handleLifecycleEvent(Event.ON_CREATE); | ||
} | ||
|
||
@Override | ||
public void onActivityStarted(@NonNull Activity activity) { | ||
if (activity.hashCode() != registrarActivityHashCode) { | ||
return; | ||
} | ||
lifecycle.handleLifecycleEvent(Event.ON_START); | ||
} | ||
|
||
@Override | ||
public void onActivityResumed(@NonNull Activity activity) { | ||
if (activity.hashCode() != registrarActivityHashCode) { | ||
return; | ||
} | ||
lifecycle.handleLifecycleEvent(Event.ON_RESUME); | ||
} | ||
|
||
@Override | ||
public void onActivityPaused(@NonNull Activity activity) { | ||
if (activity.hashCode() != registrarActivityHashCode) { | ||
return; | ||
} | ||
lifecycle.handleLifecycleEvent(Event.ON_PAUSE); | ||
} | ||
|
||
@Override | ||
public void onActivityStopped(@NonNull Activity activity) { | ||
if (activity.hashCode() != registrarActivityHashCode) { | ||
return; | ||
} | ||
lifecycle.handleLifecycleEvent(Event.ON_STOP); | ||
} | ||
|
||
@Override | ||
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {} | ||
|
||
@Override | ||
public void onActivityDestroyed(@NonNull Activity activity) { | ||
if (activity.hashCode() != registrarActivityHashCode) { | ||
return; | ||
} | ||
activity.getApplication().unregisterActivityLifecycleCallbacks(this); | ||
lifecycle.handleLifecycleEvent(Event.ON_DESTROY); | ||
} | ||
|
||
@NonNull | ||
@Override | ||
public Lifecycle getLifecycle() { | ||
return lifecycle; | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
...erax/android/src/test/java/io/flutter/plugins/camerax/CameraAndroidCameraxPluginTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
package io.flutter.plugins.camerax; | ||
|
||
import static org.mockito.Mockito.any; | ||
import static org.mockito.Mockito.doNothing; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.spy; | ||
import static org.mockito.Mockito.verify; | ||
import static org.mockito.Mockito.when; | ||
import static org.mockito.Mockito.withSettings; | ||
|
||
import android.app.Activity; | ||
import android.app.Application; | ||
import androidx.lifecycle.LifecycleOwner; | ||
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding; | ||
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.mockito.Mock; | ||
import org.mockito.junit.MockitoJUnit; | ||
import org.mockito.junit.MockitoRule; | ||
|
||
public class CameraAndroidCameraxPluginTest { | ||
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); | ||
|
||
@Mock ActivityPluginBinding activityPluginBinding; | ||
@Mock FlutterPluginBinding flutterPluginBinding; | ||
|
||
@Test | ||
public void onAttachedToActivity_setsLifecycleOwnerAsActivityIfLifecycleOwner() { | ||
CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); | ||
Activity mockActivity = | ||
mock(Activity.class, withSettings().extraInterfaces(LifecycleOwner.class)); | ||
ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = | ||
mock(ProcessCameraProviderHostApiImpl.class); | ||
|
||
doNothing().when(plugin).setUp(any(), any(), any()); | ||
when(activityPluginBinding.getActivity()).thenReturn(mockActivity); | ||
|
||
plugin.processCameraProviderHostApiImpl = mockProcessCameraProviderHostApiImpl; | ||
plugin.systemServicesHostApiImpl = mock(SystemServicesHostApiImpl.class); | ||
|
||
plugin.onAttachedToEngine(flutterPluginBinding); | ||
plugin.onAttachedToActivity(activityPluginBinding); | ||
|
||
verify(mockProcessCameraProviderHostApiImpl).setLifecycleOwner(any(LifecycleOwner.class)); | ||
} | ||
|
||
@Test | ||
public void | ||
onAttachedToActivity_setsLifecycleOwnerAsProxyLifecycleProviderIfActivityNotLifecycleOwner() { | ||
CameraAndroidCameraxPlugin plugin = spy(new CameraAndroidCameraxPlugin()); | ||
Activity mockActivity = mock(Activity.class); | ||
ProcessCameraProviderHostApiImpl mockProcessCameraProviderHostApiImpl = | ||
mock(ProcessCameraProviderHostApiImpl.class); | ||
|
||
doNothing().when(plugin).setUp(any(), any(), any()); | ||
when(activityPluginBinding.getActivity()).thenReturn(mockActivity); | ||
when(mockActivity.getApplication()).thenReturn(mock(Application.class)); | ||
|
||
plugin.processCameraProviderHostApiImpl = mockProcessCameraProviderHostApiImpl; | ||
plugin.systemServicesHostApiImpl = mock(SystemServicesHostApiImpl.class); | ||
|
||
plugin.onAttachedToEngine(flutterPluginBinding); | ||
plugin.onAttachedToActivity(activityPluginBinding); | ||
|
||
verify(mockProcessCameraProviderHostApiImpl) | ||
.setLifecycleOwner(any(ProxyLifecycleProvider.class)); | ||
} | ||
} |
121 changes: 121 additions & 0 deletions
121
..._camerax/android/src/test/java/io/flutter/plugins/camerax/ProxyLifecycleProviderTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// Copyright 2013 The Flutter Authors. All rights reserved. | ||
// Use of this source code is governed by a BSD-style license that can be | ||
// found in the LICENSE file. | ||
|
||
package io.flutter.plugins.camerax; | ||
|
||
import static org.junit.Assert.assertEquals; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.verify; | ||
import static org.mockito.Mockito.verifyNoInteractions; | ||
import static org.mockito.Mockito.when; | ||
|
||
import android.app.Activity; | ||
import android.app.Application; | ||
import android.os.Bundle; | ||
import androidx.lifecycle.Lifecycle.Event; | ||
import androidx.lifecycle.LifecycleRegistry; | ||
import org.junit.Before; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.mockito.Mock; | ||
import org.mockito.junit.MockitoJUnit; | ||
import org.mockito.junit.MockitoRule; | ||
|
||
public class ProxyLifecycleProviderTest { | ||
@Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); | ||
|
||
@Mock Activity activity; | ||
@Mock Application application; | ||
@Mock LifecycleRegistry mockLifecycleRegistry; | ||
|
||
private final int testHashCode = 27; | ||
|
||
@Before | ||
public void setUp() { | ||
when(activity.getApplication()).thenReturn(application); | ||
} | ||
|
||
@Test | ||
public void onActivityCreated_handlesOnCreateEvent() { | ||
ProxyLifecycleProvider proxyLifecycleProvider = new ProxyLifecycleProvider(activity); | ||
Bundle mockBundle = mock(Bundle.class); | ||
|
||
proxyLifecycleProvider.lifecycle = mockLifecycleRegistry; | ||
|
||
proxyLifecycleProvider.onActivityCreated(activity, mockBundle); | ||
|
||
verify(mockLifecycleRegistry).handleLifecycleEvent(Event.ON_CREATE); | ||
} | ||
|
||
@Test | ||
public void onActivityStarted_handlesOnActivityStartedEvent() { | ||
ProxyLifecycleProvider proxyLifecycleProvider = new ProxyLifecycleProvider(activity); | ||
proxyLifecycleProvider.lifecycle = mockLifecycleRegistry; | ||
|
||
proxyLifecycleProvider.onActivityStarted(activity); | ||
|
||
verify(mockLifecycleRegistry).handleLifecycleEvent(Event.ON_START); | ||
} | ||
|
||
@Test | ||
public void onActivityResumed_handlesOnActivityResumedEvent() { | ||
ProxyLifecycleProvider proxyLifecycleProvider = new ProxyLifecycleProvider(activity); | ||
proxyLifecycleProvider.lifecycle = mockLifecycleRegistry; | ||
|
||
proxyLifecycleProvider.onActivityResumed(activity); | ||
|
||
verify(mockLifecycleRegistry).handleLifecycleEvent(Event.ON_RESUME); | ||
} | ||
|
||
@Test | ||
public void onActivityPaused_handlesOnActivityPausedEvent() { | ||
ProxyLifecycleProvider proxyLifecycleProvider = new ProxyLifecycleProvider(activity); | ||
proxyLifecycleProvider.lifecycle = mockLifecycleRegistry; | ||
|
||
proxyLifecycleProvider.onActivityPaused(activity); | ||
|
||
verify(mockLifecycleRegistry).handleLifecycleEvent(Event.ON_PAUSE); | ||
} | ||
|
||
@Test | ||
public void onActivityStopped_handlesOnActivityStoppedEvent() { | ||
ProxyLifecycleProvider proxyLifecycleProvider = new ProxyLifecycleProvider(activity); | ||
proxyLifecycleProvider.lifecycle = mockLifecycleRegistry; | ||
|
||
proxyLifecycleProvider.onActivityStopped(activity); | ||
|
||
verify(mockLifecycleRegistry).handleLifecycleEvent(Event.ON_STOP); | ||
} | ||
|
||
@Test | ||
public void onActivityDestroyed_handlesOnActivityDestroyed() { | ||
ProxyLifecycleProvider proxyLifecycleProvider = new ProxyLifecycleProvider(activity); | ||
proxyLifecycleProvider.lifecycle = mockLifecycleRegistry; | ||
|
||
proxyLifecycleProvider.onActivityDestroyed(activity); | ||
|
||
verify(mockLifecycleRegistry).handleLifecycleEvent(Event.ON_DESTROY); | ||
} | ||
|
||
@Test | ||
public void onActivitySaveInstanceState_doesNotHandleLifecycleEvvent() { | ||
ProxyLifecycleProvider proxyLifecycleProvider = new ProxyLifecycleProvider(activity); | ||
Bundle mockBundle = mock(Bundle.class); | ||
|
||
proxyLifecycleProvider.lifecycle = mockLifecycleRegistry; | ||
|
||
proxyLifecycleProvider.onActivitySaveInstanceState(activity, mockBundle); | ||
|
||
verifyNoInteractions(mockLifecycleRegistry); | ||
} | ||
|
||
@Test | ||
public void getLifecycle_returnsExpectedLifecycle() { | ||
ProxyLifecycleProvider proxyLifecycleProvider = new ProxyLifecycleProvider(activity); | ||
|
||
proxyLifecycleProvider.lifecycle = mockLifecycleRegistry; | ||
|
||
assertEquals(proxyLifecycleProvider.getLifecycle(), mockLifecycleRegistry); | ||
} | ||
} |
Oops, something went wrong.