UPDATE: Works on Emulator with Android Oreo (8.X). I have the possibility to do changes right to the android sources, so it would also help if someone knews what in the android sources I have to change or update to get this working (so I don't really need an Android 7 workaround for this. An update to Android 8 though is not possible.)
I'm having a SurfaceView inside a FrameLayout. The SurfaceView usually displays a video, for example purposes I'm actually drawing an image. The problem is, if I'm setting the size of the FrameLayout (or the SurfaceView) above 10.000 pixels in width, it gets cropped on the left side.
Tested on Android 7.1.1 (on a device and Emulator: Android TV (1080p) API 25
public class TestActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//add surfaceview
TestSurfaceView testSurfaceView = new TestSurfaceView(this);
setContentView(testSurfaceView);
//resize
FrameLayout.LayoutParams bgParams = (FrameLayout.LayoutParams) testSurfaceView.getLayoutParams();
//testcase full hd - working
bgParams.width = 1920;
//testcase 2 - working - each segment is 330px as 9900 / 1920 * 64 (default segment width) == 330
//bgParams.width = 9900;
//testcase 3 - working
//bgParams.width = 10000;
//testcase 4 - not working - each segment is 335px which is correct but first cell gets cropped by exactly 50px to the left
//bgParams.width = 10050;
bgParams.height = (int)Math.floor(bgParams.width * (9d/16d)); //16:9
testSurfaceView.setX(0); //doesnt help
/*
Also the position counts into the 10000px limitation as you can see on following testcases
*/
/*
bgParams.width = 9900;
bgParams.height = (int)Math.floor(bgParams.width * (9d/16d)); //16:9
//works - as 9900 + 90 < 10000
testSurfaceView.setX(90);
//doesnt work, crops 50px to the left - 9900 + 150 -> 10050
testSurfaceView.setX(150);
*/
}
}
public class TestSurfaceView extends SurfaceView implements SurfaceHolder.Callback
{
public TestSurfaceView(TestActivity context) {
super(context);
SurfaceHolder holder = this.getHolder();
holder.addCallback(this);
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder)
{
//load bitmap from file
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/testimg.png", options);
Canvas c = surfaceHolder.lockCanvas();
Rect rect = new Rect();
rect.set(0,0, 1920, 1080); //image size
Rect destRect = new Rect();
destRect.set(0, 0, this.getWidth(), this.getHeight());
//draw the image on the surface
c.drawBitmap(bitmap, rect, destRect, null);
surfaceHolder.unlockCanvasAndPost(c);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
}
styles.xml - for the theme
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="android:Theme.Material.Light.NoActionBar.Fullscreen">
<!-- Customize your theme here. -->
</style>
</resources>
The code above produces following output, which is correct.
If I change the bgParams.width
to 9600 - it scales up correctly and still displays starting from the left edge of the image:
But if I change the code to e.g. 10050, the image gets cropped by 50 pixels to the left.
If I set:
destRect.set(50, 0, this.getWidth(), this.getHeight());
It gets displayed correctly, but as I can't do that for the MediaPlayer and it's super weird, I'm trying to find a good solution.
I also tried setting the sizes directly on the SurfaceView and instead of changing the LayoutParams, I tried setting scaleX and scaleY of the Framelayout but ended up with the same results.
(btw. opengl max texture size is about 16000px - setting it above the ~16000px results in a black screen and an exception, so that is not the cause of the problem)
Update: Posted all sources. Anyway here is the complete android studio project: WeTransfer project download link