|
|
@ -1,6 +1,8 @@ |
|
|
|
package com.otaliastudios.cameraview.internal; |
|
|
|
package com.otaliastudios.cameraview.internal; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import android.app.Activity; |
|
|
|
import android.content.Context; |
|
|
|
import android.content.Context; |
|
|
|
|
|
|
|
import android.content.res.Configuration; |
|
|
|
import android.hardware.SensorManager; |
|
|
|
import android.hardware.SensorManager; |
|
|
|
import androidx.annotation.NonNull; |
|
|
|
import androidx.annotation.NonNull; |
|
|
|
import androidx.annotation.VisibleForTesting; |
|
|
|
import androidx.annotation.VisibleForTesting; |
|
|
@ -9,6 +11,7 @@ import android.hardware.display.DisplayManager; |
|
|
|
import android.os.Build; |
|
|
|
import android.os.Build; |
|
|
|
import android.os.Handler; |
|
|
|
import android.os.Handler; |
|
|
|
import android.os.Looper; |
|
|
|
import android.os.Looper; |
|
|
|
|
|
|
|
import android.view.View; |
|
|
|
import android.view.Display; |
|
|
|
import android.view.Display; |
|
|
|
import android.view.OrientationEventListener; |
|
|
|
import android.view.OrientationEventListener; |
|
|
|
import android.view.Surface; |
|
|
|
import android.view.Surface; |
|
|
@ -18,6 +21,36 @@ import android.view.WindowManager; |
|
|
|
* Helps with keeping track of both device orientation (which changes when device is rotated) |
|
|
|
* Helps with keeping track of both device orientation (which changes when device is rotated) |
|
|
|
* and the display offset (which depends on the activity orientation wrt the device default |
|
|
|
* and the display offset (which depends on the activity orientation wrt the device default |
|
|
|
* orientation). |
|
|
|
* orientation). |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Note: any change in the display offset should restart the camera engine, because it reads |
|
|
|
|
|
|
|
* from the angles container at startup and computes size based on that. This is tricky because |
|
|
|
|
|
|
|
* activity behavior can differ: |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* - if activity is locked to some orientation, {@link #mDisplayOffset} won't change, and |
|
|
|
|
|
|
|
* {@link View#onConfigurationChanged(Configuration)} won't be called. |
|
|
|
|
|
|
|
* The library will work fine. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* - if the activity is unlocked and does NOT handle orientation changes with android:configChanges, |
|
|
|
|
|
|
|
* the actual behavior differs depending on the rotation. |
|
|
|
|
|
|
|
* - the configuration callback is never called, of course. |
|
|
|
|
|
|
|
* - for 90°/-90° rotations, the activity is recreated. Sometime you get {@link #mDisplayOffset} |
|
|
|
|
|
|
|
* callback before destruction, sometimes you don't - in any case it's going to recreate. |
|
|
|
|
|
|
|
* - for 180°/-180°, the activity is NOT recreated! But we can rely on {@link #mDisplayOffset} |
|
|
|
|
|
|
|
* changing with a 180 delta and restart the engine. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* - lastly, if the activity is unlocked and DOES handle orientation changes with android:configChanges, |
|
|
|
|
|
|
|
* as it will often be the case in a modern Compose app, |
|
|
|
|
|
|
|
* - you always get the {@link #mDisplayOffset} callback |
|
|
|
|
|
|
|
* - for 90°/-90° rotations, the view also gets the configuration changed callback. |
|
|
|
|
|
|
|
* - for 180°/-180°, the view won't get it because configuration only cares about portrait vs. landscape. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* In practice, since we don't control the activity and we can't easily inspect the configChanges |
|
|
|
|
|
|
|
* flags at runtime, a good solution is to always restart when the display offset changes. We might |
|
|
|
|
|
|
|
* do useless restarts in one rare scenario (unlocked, no android:configChanges, 90° rotation, |
|
|
|
|
|
|
|
* display offset callback received before destruction) but that's acceptable. |
|
|
|
|
|
|
|
* |
|
|
|
|
|
|
|
* Tried to avoid that by looking at {@link Activity#isChangingConfigurations()}, but it's always |
|
|
|
|
|
|
|
* false by the time the display offset callback is invoked. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class OrientationHelper { |
|
|
|
public class OrientationHelper { |
|
|
|
|
|
|
|
|
|
|
@ -26,7 +59,7 @@ public class OrientationHelper { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public interface Callback { |
|
|
|
public interface Callback { |
|
|
|
void onDeviceOrientationChanged(int deviceOrientation); |
|
|
|
void onDeviceOrientationChanged(int deviceOrientation); |
|
|
|
void onDisplayOffsetChanged(int displayOffset, boolean willRecreate); |
|
|
|
void onDisplayOffsetChanged(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private final Handler mHandler = new Handler(Looper.getMainLooper()); |
|
|
|
private final Handler mHandler = new Handler(Looper.getMainLooper()); |
|
|
@ -87,9 +120,7 @@ public class OrientationHelper { |
|
|
|
int newDisplayOffset = findDisplayOffset(); |
|
|
|
int newDisplayOffset = findDisplayOffset(); |
|
|
|
if (newDisplayOffset != oldDisplayOffset) { |
|
|
|
if (newDisplayOffset != oldDisplayOffset) { |
|
|
|
mDisplayOffset = newDisplayOffset; |
|
|
|
mDisplayOffset = newDisplayOffset; |
|
|
|
// With 180 degrees flips, the activity is not recreated.
|
|
|
|
mCallback.onDisplayOffsetChanged(); |
|
|
|
boolean willRecreate = Math.abs(newDisplayOffset - oldDisplayOffset) != 180; |
|
|
|
|
|
|
|
mCallback.onDisplayOffsetChanged(newDisplayOffset, willRecreate); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|