|  |  |  | @ -1,6 +1,8 @@ | 
			
		
	
		
			
				
					|  |  |  |  | package com.otaliastudios.cameraview.internal; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | import android.app.Activity; | 
			
		
	
		
			
				
					|  |  |  |  | import android.content.Context; | 
			
		
	
		
			
				
					|  |  |  |  | import android.content.res.Configuration; | 
			
		
	
		
			
				
					|  |  |  |  | import android.hardware.SensorManager; | 
			
		
	
		
			
				
					|  |  |  |  | import androidx.annotation.NonNull; | 
			
		
	
		
			
				
					|  |  |  |  | import androidx.annotation.VisibleForTesting; | 
			
		
	
	
		
			
				
					|  |  |  | @ -9,6 +11,7 @@ import android.hardware.display.DisplayManager; | 
			
		
	
		
			
				
					|  |  |  |  | import android.os.Build; | 
			
		
	
		
			
				
					|  |  |  |  | import android.os.Handler; | 
			
		
	
		
			
				
					|  |  |  |  | import android.os.Looper; | 
			
		
	
		
			
				
					|  |  |  |  | import android.view.View; | 
			
		
	
		
			
				
					|  |  |  |  | import android.view.Display; | 
			
		
	
		
			
				
					|  |  |  |  | import android.view.OrientationEventListener; | 
			
		
	
		
			
				
					|  |  |  |  | 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) | 
			
		
	
		
			
				
					|  |  |  |  |  * and the display offset (which depends on the activity orientation wrt the device default | 
			
		
	
		
			
				
					|  |  |  |  |  * 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 { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -26,7 +59,7 @@ public class OrientationHelper { | 
			
		
	
		
			
				
					|  |  |  |  |      */ | 
			
		
	
		
			
				
					|  |  |  |  |     public interface Callback { | 
			
		
	
		
			
				
					|  |  |  |  |         void onDeviceOrientationChanged(int deviceOrientation); | 
			
		
	
		
			
				
					|  |  |  |  |         void onDisplayOffsetChanged(int displayOffset, boolean willRecreate); | 
			
		
	
		
			
				
					|  |  |  |  |         void onDisplayOffsetChanged(); | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     private final Handler mHandler = new Handler(Looper.getMainLooper()); | 
			
		
	
	
		
			
				
					|  |  |  | @ -87,9 +120,7 @@ public class OrientationHelper { | 
			
		
	
		
			
				
					|  |  |  |  |                     int newDisplayOffset = findDisplayOffset(); | 
			
		
	
		
			
				
					|  |  |  |  |                     if (newDisplayOffset != oldDisplayOffset) { | 
			
		
	
		
			
				
					|  |  |  |  |                         mDisplayOffset = newDisplayOffset; | 
			
		
	
		
			
				
					|  |  |  |  |                         // With 180 degrees flips, the activity is not recreated.
 | 
			
		
	
		
			
				
					|  |  |  |  |                         boolean willRecreate = Math.abs(newDisplayOffset - oldDisplayOffset) != 180; | 
			
		
	
		
			
				
					|  |  |  |  |                         mCallback.onDisplayOffsetChanged(newDisplayOffset, willRecreate); | 
			
		
	
		
			
				
					|  |  |  |  |                         mCallback.onDisplayOffsetChanged(); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             }; | 
			
		
	
	
		
			
				
					|  |  |  | 
 |