Screen scaling code for landscape and portrait modes.

This commit is contained in:
James Sanford 2012-09-20 22:02:01 -07:00
parent f178c50fac
commit fb6893468a
4 changed files with 110 additions and 23 deletions

View File

@ -11,7 +11,7 @@
<uses-feature android:name="android.hardware.touchscreen.multitouch.distinct" android:required="false"/>
<application android:icon="@drawable/icon" android:label="@string/app_name" android:description="@string/app_description" android:hardwareAccelerated="true">
<activity android:name="KegsMain" android:launchMode="singleInstance" android:configChanges="orientation|keyboardHidden|screenSize" android:windowSoftInputMode="stateAlwaysVisible|adjustPan">
<activity android:name="KegsMain" android:launchMode="singleInstance" android:configChanges="orientation|keyboard|keyboardHidden|screenSize" android:windowSoftInputMode="stateAlwaysVisible|adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

View File

@ -6,8 +6,8 @@
<com.froop.app.kegs.KegsView
android:id="@+id/kegsview"
android:layout_width="704px"
android:layout_height="462px"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
/>

View File

@ -1,5 +1,6 @@
package com.froop.app.kegs;
import android.app.ActionBar;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@ -7,6 +8,7 @@ import android.app.DialogFragment;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.AsyncTask;
import android.util.Log;
@ -188,6 +190,57 @@ public class KegsMain extends Activity implements KegsKeyboard.StickyReset {
}
}
private void setScreenSize() {
final int width = getResources().getDisplayMetrics().widthPixels;
final int height = getResources().getDisplayMetrics().heightPixels;
// If we can fit at least 90% of a scaled screen into the display area, do it.
// If we hit less than 100% height, turn off system action bar and title.
// If ((400 + 32) * scale) > height, then crop border.
float scaleX = 1.0f;
float scaleY = 1.0f;
boolean crop = false;
// Force integer scaling on X axis.
scaleX = (float)Math.round((width * 0.9) / 640);
// TODO: Fix '48' hack being used for system buttons or soft buttons.
scaleY = Math.min(scaleX, (height - 48) / 400.0f);
// If Y would be compressed in a weird way, reduce the scale and use 1:1.
if ((scaleX - scaleY) > 0.5) {
scaleX = Math.max(1, scaleX - 1);
scaleY = scaleX;
}
if (height < ((400 + 64) * scaleY)) {
ActionBar actionBar = getActionBar();
if (actionBar != null && actionBar.isShowing()) {
actionBar.hide();
}
} else {
ActionBar actionBar = getActionBar();
if (actionBar != null && !actionBar.isShowing()) {
actionBar.show();
}
}
// TODO: Fix '32' and '64' for software buttons and window decorations.
if (height < ((400 + 32 + 64) * scaleY)) {
crop = true;
}
Log.w("kegs", "using scale " + scaleX + ":" + scaleY + " " + crop);
mKegsView.setScale(scaleX, scaleY, crop);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
setScreenSize();
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
return mKegsKeyboard.keyEvent(event) || super.dispatchKeyEvent(event);
@ -206,6 +259,7 @@ public class KegsMain extends Activity implements KegsKeyboard.StickyReset {
setContentView(R.layout.main);
mKegsView = (KegsView)findViewById(R.id.kegsview);
setScreenSize(); // This causes an unnecessary requestLayout of KegsView.
mKegsTouch = new KegsTouch(mKegsView.getEventQueue());
final GestureDetector inputDetect = new GestureDetector(this, mKegsTouch);

View File

@ -23,6 +23,11 @@ class KegsView extends SurfaceView implements SurfaceHolder.Callback {
private boolean mPaused = false;
private boolean mReady = false;
// Bitmap draw options.
private boolean mScaled = false;
private float mScaleFactorX = 1.0f;
private float mScaleFactorY = 1.0f;
protected ConcurrentLinkedQueue<Event.KegsEvent> mEventQueue = new ConcurrentLinkedQueue<Event.KegsEvent>();
class KegsThread extends Thread {
@ -32,7 +37,8 @@ class KegsView extends SurfaceView implements SurfaceHolder.Callback {
private Context mContext;
private final ReentrantLock mSurfaceLock = new ReentrantLock();
private final ReentrantLock mPauseLock = new ReentrantLock();
private final Rect mRect = new Rect(0, 0, mA2Width, mA2Height);
private Rect mRectSrc = new Rect(0, 0, mA2Width, mA2Height);
private Rect mRectDst = new Rect(0, 0, mA2Width, mA2Height);
public KegsThread(SurfaceHolder surfaceHolder, Context context) {
mSurfaceHolder = surfaceHolder;
@ -45,20 +51,22 @@ class KegsView extends SurfaceView implements SurfaceHolder.Callback {
// Typically called by the native thread, but this can also be
// called on the UI thread via setHaveSurface.
protected void updateScreen() {
if (!mHaveSurface) {
return;
}
mSurfaceLock.lock();
try {
mCanvas = mSurfaceHolder.lockCanvas(); // Use mRect ?
if (!mHaveSurface) {
return; // unlock with finally
}
mCanvas = mSurfaceHolder.lockCanvas(); // Use Rect ?
if(mCanvas != null) {
// Scaling tests: save/scale/restore, or drawBitmap into a destination rect.
// mCanvas.save();
mCanvas.drawARGB(255, 0, 0, 0);
// mCanvas.scale(1.8f, 1.8f);
mCanvas.drawBitmap(mBitmap, 0, 0, null);
// mCanvas.restore();
// Doesn't work well, but consider eliminating the border instead, for phones.
mCanvas.drawARGB(255, 0, 0, 0); // TODO: Figure out why necessary.
if (!mScaled) {
mCanvas.drawBitmap(mBitmap, mRectSrc, mRectDst, null);
} else {
mCanvas.save();
mCanvas.scale(mScaleFactorX, mScaleFactorY);
mCanvas.drawBitmap(mBitmap, mRectSrc, mRectDst, null);
mCanvas.restore();
}
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
mCanvas = null;
}
@ -117,6 +125,26 @@ class KegsView extends SurfaceView implements SurfaceHolder.Callback {
return mPauseLock.hasQueuedThreads();
}
public void setScale(float scaleFactorX, float scaleFactorY, boolean cropBorder) {
mSurfaceLock.lock();
if (scaleFactorX == 1.0f && scaleFactorY == 1.0f) {
mScaled = false;
} else {
mScaled = true;
}
mScaleFactorX = scaleFactorX;
mScaleFactorY = scaleFactorY;
if (cropBorder) {
mRectSrc = new Rect(0, 32, mA2Width, mA2Height);
mRectDst = new Rect(0, 0, mA2Width, mA2Height - 32);
} else {
mRectSrc = new Rect(0, 0, mA2Width, mA2Height);
mRectDst = new Rect(0, 0, mA2Width, mA2Height);
}
mSurfaceLock.unlock();
updateScreen();
}
public void setHaveSurface(boolean haveSurface) {
mSurfaceLock.lock();
mHaveSurface = haveSurface;
@ -127,11 +155,6 @@ class KegsView extends SurfaceView implements SurfaceHolder.Callback {
updateScreen();
}
}
public void setSurfaceSize(int width, int height) {
// consider.. mSurfaceLock.lock(); update sizes and bitmap; unlock
}
}
private Context mContext;
@ -175,9 +198,10 @@ class KegsView extends SurfaceView implements SurfaceHolder.Callback {
// }
}
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
thread.setSurfaceSize(width, height);
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension((int)(mA2Width * mScaleFactorX),
(int)(mA2Height * mScaleFactorY));
}
public native String stringFromJNI();
@ -192,6 +216,15 @@ class KegsView extends SurfaceView implements SurfaceHolder.Callback {
}
}
public void setScale(float scaleFactorX, float scaleFactorY, boolean cropBorder) {
thread.setScale(scaleFactorX, scaleFactorY, cropBorder);
requestLayout();
}
public void surfaceChanged(SurfaceHolder holder,
int format, int width, int height) {
}
// The surface callbacks are occasionally called in between pause and resume.
public void surfaceCreated(SurfaceHolder holder) {