diff --git a/packages/camera/camera_android_camerax/CHANGELOG.md b/packages/camera/camera_android_camerax/CHANGELOG.md index ad47eaa6b88..913a5eeadbb 100644 --- a/packages/camera/camera_android_camerax/CHANGELOG.md +++ b/packages/camera/camera_android_camerax/CHANGELOG.md @@ -1,3 +1,9 @@ +## 0.6.17 + +* Replaces `BroadcastReceiver` usage with an `OrientationEventListener` to detect changes in device + orientation to fix issue where some devices do not report changes in device configuration if it + is rotated between the same sort of orientation (landscape/portrait). + ## 0.6.16 * Fixes incorrect camera preview rotation for landscape-oriented devices. diff --git a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/DeviceOrientationManager.java b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/DeviceOrientationManager.java index bbc0b7d7ca7..382dd2de8fb 100644 --- a/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/DeviceOrientationManager.java +++ b/packages/camera/camera_android_camerax/android/src/main/java/io/flutter/plugins/camerax/DeviceOrientationManager.java @@ -10,8 +10,10 @@ import android.content.IntentFilter; import android.content.res.Configuration; import android.view.Display; +import android.view.OrientationEventListener; import android.view.Surface; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import io.flutter.embedding.engine.systemchannels.PlatformChannel; import io.flutter.embedding.engine.systemchannels.PlatformChannel.DeviceOrientation; @@ -28,6 +30,8 @@ public class DeviceOrientationManager { private PlatformChannel.DeviceOrientation lastOrientation; private BroadcastReceiver broadcastReceiver; + @VisibleForTesting @Nullable protected OrientationEventListener orientationEventListener; + DeviceOrientationManager(DeviceOrientationManagerProxyApi api) { this.api = api; } @@ -38,39 +42,46 @@ Context getContext() { } /** - * Starts listening to the device's sensors or UI for orientation updates. + * Starts listening to the device's sensors for device orientation updates. * *
When orientation information is updated, the callback method of the {@link * DeviceOrientationManagerProxyApi} is called with the new orientation. - * - *
If the device's ACCELEROMETER_ROTATION setting is enabled the {@link - * DeviceOrientationManager} will report orientation updates based on the sensor information. If - * the ACCELEROMETER_ROTATION is disabled the {@link DeviceOrientationManager} will fallback to - * the deliver orientation updates based on the UI orientation. */ public void start() { stop(); - broadcastReceiver = - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - handleUIOrientationChange(); - } - }; - getContext().registerReceiver(broadcastReceiver, orientationIntentFilter); - broadcastReceiver.onReceive(getContext(), null); + // Listen for changes in device orientation at the default rate that is suitable for monitoring + // typical screen orientation changes. + orientationEventListener = createOrientationEventListener(); + orientationEventListener.enable(); + } + + @VisibleForTesting + @NonNull + /** + * Creates an {@link OrientationEventListener} that will call the callback method of the {@link + * DeviceOrientationManagerProxyApi} whenever it is notified of a new device orientation and this + * {@code DeviceOrientationManager} instance determines that the orientation of the device {@link + * Configuration} has changed. + */ + protected OrientationEventListener createOrientationEventListener() { + return new OrientationEventListener(getContext()) { + @Override + public void onOrientationChanged(int orientation) { + handleUIOrientationChange(); + } + }; } /** Stops listening for orientation updates. */ public void stop() { - if (broadcastReceiver == null) { + if (orientationEventListener == null) { return; } - getContext().unregisterReceiver(broadcastReceiver); - broadcastReceiver = null; - lastOrientation = null; + + orientationEventListener.disable(); + orientationEventListener = null; } /** @@ -87,8 +98,7 @@ void handleUIOrientationChange() { } /** - * Handles orientation changes coming from either the device's sensors or the - * OrientationIntentFilter. + * Handles orientation changes coming from the device's sensors. * *
This method is visible for testing purposes only and should never be used outside this
* class.
diff --git a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/DeviceOrientationManagerTest.java b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/DeviceOrientationManagerTest.java
index b75774f5e21..56456cf4ecc 100644
--- a/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/DeviceOrientationManagerTest.java
+++ b/packages/camera/camera_android_camerax/android/src/test/java/io/flutter/plugins/camerax/DeviceOrientationManagerTest.java
@@ -5,11 +5,13 @@
package io.flutter.plugins.camerax;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockStatic;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -18,15 +20,14 @@
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.provider.Settings;
import android.view.Display;
+import android.view.OrientationEventListener;
import android.view.Surface;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import io.flutter.embedding.engine.systemchannels.PlatformChannel.DeviceOrientation;
import org.junit.Before;
import org.junit.Test;
-import org.mockito.MockedStatic;
public class DeviceOrientationManagerTest {
private Activity mockActivity;
@@ -63,21 +64,40 @@ Display getDisplay() {
}
@Test
- public void handleUIOrientationChange_shouldSendMessageWhenSensorAccessIsAllowed() {
- try (MockedStatic