title: How Do I Determine the Default Orientation of Camera Preview Frames?
body: <p>I am trying (again) to create camera preview logic that actually works properly, for <strong>all scenarios</strong>:</p>
  
  <ul>
  <li>any device: phone, tablet, toaster, whatever</li>
  <li>any camera: front-facing, rear-facing, side-facing, dog-facing, whatever</li>
  <li><code>android.hardware.Camera</code> and <code>android.hardware.camera2</code></li>
  <li>portrait and landscape device orientations</li>
  </ul>
  
  <p>Since my <code>minSdkVersion</code> is 15, and since I am not especially concerned about performance, I am trying to use a <code>TextureView</code>. And, following the advice of fadden in places like <a href="https://stackoverflow.com/a/27175434/115145">here</a> and <a href="https://stackoverflow.com/a/31657474/115145">here</a>, I am trying to use <code>setTransform()</code> on that <code>TextureView</code> with an appropriate <code>Matrix</code> that:</p>
  
  <ul>
  <li>orients the preview properly, taking device orientation into account</li>
  <li>fills the <code>TextureView</code> completely, at the cost of cropping where the <code>TextureView</code> aspect ratio does not match the preview frame aspect ratio</li>
  <li>does not stretch the image, so that a preview of a square item (e.g., a 3" square Post-It Note&reg;) shows up square in the preview</li>
  </ul>
  
  <p>In my case, the <code>TextureView</code> fills the screen, minus the status bar and navigation bar.</p>
  
  <p>Starting with the <code>adjustAspectRatio()</code> from <a href="https://github.com/google/grafika/blob/master/src/com/android/grafika/PlayMovieActivity.java" rel="noreferrer">Grafika's <code>PlayMovieActivity.java</code></a>, I now have this:</p>
  
  <pre><code>  private void adjustAspectRatio(int videoWidth, int videoHeight,
                                   int rotation) {
      if (iCanHazPhone) {
        int temp=videoWidth;
        videoWidth=videoHeight;
        videoHeight=temp;
      }
  
      int viewWidth=getWidth();
      int viewHeight=getHeight();
      double aspectRatio=(double)videoHeight/(double)videoWidth;
      int newWidth, newHeight;
  
      if (getHeight()&gt;(int)(viewWidth*aspectRatio)) {
        newWidth=(int)(viewHeight/aspectRatio);
        newHeight=viewHeight;
      }
      else {
        newWidth=viewWidth;
        newHeight=(int)(viewWidth*aspectRatio);
      }
  
      int xoff=(viewWidth-newWidth)/2;
      int yoff=(viewHeight-newHeight)/2;
  
      Matrix txform=new Matrix();
  
      getTransform(txform);
  
      float xscale=(float)newWidth/(float)viewWidth;
      float yscale=(float)newHeight/(float)viewHeight;
  
      txform.setScale(xscale, yscale);
  
      switch(rotation) {
        case Surface.ROTATION_90:
          txform.postRotate(270, newWidth/2, newHeight/2);
          break;
  
        case Surface.ROTATION_270:
          txform.postRotate(90, newWidth/2, newHeight/2);
          break;
      }
  
      txform.postTranslate(xoff, yoff);
  
      setTransform(txform);
    }
  </code></pre>
  
  <p>Here, <code>videoWidth</code> and <code>videoHeight</code> are the size of the camera preview, and the method itself is implemented on a subclass of <code>TextureView</code>. I am calling this method when I have established what the camera preview size is and after the <code>TextureView</code> itself is resized.</p>
  
  <p>This appears to be close but not completely correct. In particular, the <code>iCanHazPhone</code> hack &mdash; flipping the video width and height &mdash; is a stab in the dark, as without this, while a SONY Tablet Z2 works well, a Nexus 5 turns out horrible (stretched preview that does not fill the screen).</p>
  
  <p>With <code>iCanHazPhone</code> set to <code>true</code>, I get good results on a Nexus 5:</p>
  
  <p><img src="https://i.stack.imgur.com/w35VD.jpg" alt="Nexus 5, Camera2 Preview, Landscape, Rear-Facing Camera"></p>
  
  <p><img src="https://i.stack.imgur.com/DkWWC.png" alt="Nexus 5, Camera2 Preview, Portrait, Rear-Facing Camera"></p>
  
  <p>With <code>iCanHazPhone</code> set to <code>false</code>, I get stuff like:</p>
  
  <p><img src="https://i.stack.imgur.com/pW7hJ.png" alt="Nexus 5, Camera2 Preview, Portrait, Rear-Facing Camera, Stretched"></p>
  
  <p>Similarly, with <code>iCanHazPhone</code> set to <code>false</code>, I get good results on a SONY Tablet Z2:</p>
  
  <p><img src="https://i.stack.imgur.com/mDwjJ.png" alt="SONY Tablet Z2, Camera2 Preview, Landscape, Rear-Facing Camera"></p>
  
  <p>But if I flip it to <code>true</code>, I get:</p>
  
  <p><img src="https://i.stack.imgur.com/Sio57.png" alt="SONY Tablet Z2, Camera2 Preview, Landscape, Rear-Facing Camera, Stretched"></p>
  
  <p>My current theory is that different devices have different default camera orientations, and depending on that default orientation I need to flip the preview width and height in my calculations.</p>
  
  <p>So, the questions:</p>
  
  <ol>
  <li><p>Is the camera guaranteed (as much as anything involving Android hardware) to have a default orientation that matches the default device orientation? For example, a Nexus 9 works correctly with <code>iCanHazPhone</code> set to <code>true</code>, indicating that it's not phone vs. tablet but default-portrait vs. default-landscape.</p></li>
  <li><p>Is there a better way of dealing with this? </p></li>
  </ol>