snapshot on the way to handling rotation of the board view. Pass

orientation changes down to it (or any other interested delegate), and
have it lay its container out again. There appear to be race
conditions here: sometimes the toolbar winds up in the wrong
orientation, and on some devices the board can be blank. One problem
is that on a multi-paned device a single pane may be portrait (taller
than wide) though the whole device is in landscape mode. The big
challege is to get the view's max dimensions (and whether it's
landscape or portrait) when layout hasn't yet begun, because we that
for the jni part of layout. Messy still, but better than before and I
think progress in the right direction.
This commit is contained in:
Eric House 2016-04-04 13:43:16 -07:00
parent b6431f0373
commit ae8a66f37b
8 changed files with 146 additions and 70 deletions

View file

@ -596,6 +596,7 @@ public class BoardDelegate extends DelegateBase
m_timers = new TimerRunnable[4]; // needs to be in sync with m_timers = new TimerRunnable[4]; // needs to be in sync with
// XWTimerReason // XWTimerReason
m_view = (BoardView)findViewById( R.id.board_view ); m_view = (BoardView)findViewById( R.id.board_view );
m_view.setBoardDelegate( this );
if ( ! ABUtils.haveActionBar() ) { if ( ! ABUtils.haveActionBar() ) {
m_tradeButtons = findViewById( R.id.exchange_buttons ); m_tradeButtons = findViewById( R.id.exchange_buttons );
if ( null != m_tradeButtons ) { if ( null != m_tradeButtons ) {
@ -752,6 +753,26 @@ public class BoardDelegate extends DelegateBase
} }
} }
@Override
public void orientationChanged()
{
boolean isPortrait = isPortrait();
DbgUtils.logdf( "BoardDelegate.orientationChanged(isPortrait=%b)",
isPortrait );
positionToolbar( isPortrait );
m_view.orientationChanged();
}
private void positionToolbar( boolean isPortrait )
{
if ( null != findViewById( R.id.tbar_parent_hor ) ) {
if ( null == m_toolbar ) {
m_toolbar = new Toolbar( m_activity, this );
}
m_toolbar.setIsPortrait( isPortrait );
}
}
protected boolean onKeyDown( int keyCode, KeyEvent event ) protected boolean onKeyDown( int keyCode, KeyEvent event )
{ {
boolean handled = false; boolean handled = false;
@ -2155,12 +2176,7 @@ public class BoardDelegate extends DelegateBase
setTitle( GameUtils.getName( m_activity, m_rowid ) ); setTitle( GameUtils.getName( m_activity, m_rowid ) );
} }
if ( null != findViewById( R.id.tbar_parent_hor ) ) { positionToolbar( isPortrait() );
int orient = m_activity.getResources().getConfiguration().orientation;
boolean isLandscape = Configuration.ORIENTATION_LANDSCAPE == orient;
m_toolbar = new Toolbar( m_activity, this, isLandscape );
}
populateToolbar(); populateToolbar();
adjustTradeVisibility(); adjustTradeVisibility();

View file

@ -55,6 +55,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
private static final int PINCH_THRESHOLD = 40; private static final int PINCH_THRESHOLD = 40;
private Context m_context; private Context m_context;
private BoardDelegate m_boardDlgt;
private int m_defaultFontHt; private int m_defaultFontHt;
private int m_mediumFontHt; private int m_mediumFontHt;
private Runnable m_invalidator; private Runnable m_invalidator;
@ -142,33 +143,21 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
return wantMore; // true required to get subsequent events return wantMore; // true required to get subsequent events
} }
// private void printMode( String comment, int mode )
// {
// comment += ": ";
// switch( mode ) {
// case View.MeasureSpec.AT_MOST:
// comment += "AT_MOST";
// break;
// case View.MeasureSpec.EXACTLY:
// comment += "EXACTLY";
// break;
// case View.MeasureSpec.UNSPECIFIED:
// comment += "UNSPECIFIED";
// break;
// default:
// comment += "<bogus>";
// }
// DbgUtils.logf( comment );
// }
@Override @Override
protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec ) protected void onMeasure( int widthMeasureSpec, int heightMeasureSpec )
{ {
// One of the android sample apps ignores mode entirely: // DbgUtils.logf( "onMeasure(width: %s, height: %s)",
// int w = MeasureSpec.getSize(widthMeasureSpec); // MeasureSpec.toString( widthMeasureSpec ),
// int h = MeasureSpec.getSize(heightMeasureSpec); // MeasureSpec.toString( heightMeasureSpec ) );
// int d = w == 0 ? h : h == 0 ? w : w < h ? w : h;
// setMeasuredDimension(d, d); if ( null != m_dims ) {
if ( m_boardDlgt.isPortrait() != (m_dims.height > m_dims.width) ) {
// square possible; will break above!
Assert.assertTrue( m_dims.height != m_dims.width );
// DbgUtils.logf( "onMeasure: discarding m_dims" );
m_dims = null;
}
}
int width, height; int width, height;
m_measuredFromDims = null != m_dims; m_measuredFromDims = null != m_dims;
@ -189,8 +178,17 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
width = minWidth; width = minWidth;
} }
setMeasuredDimension( width, height ); setMeasuredDimension( width, height );
DbgUtils.logdf( "BoardView.onMeasure: calling setMeasuredDimension( width=%d, height=%d )",
width, height );
} }
// public void onSizeChanged( int width, int height, int oldWidth, int oldHeight )
// {
// DbgUtils.logf( "BoardView.onSizeChanged(): width: %d => %d; height: %d => %d",
// oldWidth, width, oldHeight, height );
// super.onSizeChanged( width, height, oldWidth, oldHeight );
// }
// This will be called from the UI thread // This will be called from the UI thread
@Override @Override
protected void onDraw( Canvas canvas ) protected void onDraw( Canvas canvas )
@ -268,6 +266,11 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
return layoutDone; return layoutDone;
} // layoutBoardOnce } // layoutBoardOnce
protected void setBoardDelegate( BoardDelegate dlgt )
{
m_boardDlgt = dlgt;
}
// BoardHandler interface implementation // BoardHandler interface implementation
public void startHandling( Activity parent, JNIThread thread, public void startHandling( Activity parent, JNIThread thread,
XwJNI.GamePtr gamePtr, CurGameInfo gi, XwJNI.GamePtr gamePtr, CurGameInfo gi,
@ -334,6 +337,12 @@ public class BoardView extends View implements BoardHandler, SyncedDraw {
}); });
} }
protected void orientationChanged()
{
m_dims = null;
requestLayout();
}
public void setInTrade( boolean inTrade ) public void setInTrade( boolean inTrade )
{ {
if ( null != m_canvas ) { if ( null != m_canvas ) {

View file

@ -19,6 +19,7 @@
package org.eehouse.android.xw4; package org.eehouse.android.xw4;
import android.graphics.Rect;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
@ -86,7 +87,8 @@ public class DelegateBase implements DlgClickNotify,
protected void onDestroy() {} protected void onDestroy() {}
protected void onWindowFocusChanged( boolean hasFocus ) {} protected void onWindowFocusChanged( boolean hasFocus ) {}
protected boolean onBackPressed() { return false; } protected boolean onBackPressed() { return false; }
public void orientationChanged() {}
protected void requestWindowFeature( int feature ) {} protected void requestWindowFeature( int feature ) {}
// Fragments only // Fragments only
@ -232,6 +234,29 @@ public class DelegateBase implements DlgClickNotify,
} }
} }
protected boolean isPortrait()
{
int[] containerDims = new int[2];
getContainerDims( containerDims );
boolean result = containerDims[0] < containerDims[1];
DbgUtils.logdf( "%s.isPortrait() => %b", getClass().getName(), result );
return result;
}
protected void getContainerDims( int[] outDims )
{
if ( m_activity instanceof FragActivity ) {
((FragActivity)m_activity).getFragmentDims( outDims );
} else {
Rect rect = new Rect();
m_rootView.getWindowVisibleDisplayFrame( rect );
outDims[0] = rect.width();
outDims[1] = rect.height();
}
DbgUtils.logdf( "getContainerDims(): width => %d, height => %d",
outDims[0], outDims[1] );
}
protected String getString( int resID, Object... params ) protected String getString( int resID, Object... params )
{ {
return LocUtils.getString( m_activity, resID, params ); return LocUtils.getString( m_activity, resID, params );

View file

@ -1,6 +1,6 @@
/* -*- compile-command: "find-and-ant.sh debug install"; -*- */ /* -*- compile-command: "find-and-ant.sh debug install"; -*- */
/* /*
* Copyright 2014 by Eric House (xwords@eehouse.org). All rights * Copyright 2014-2016 by Eric House (xwords@eehouse.org). All rights
* reserved. * reserved.
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -20,6 +20,7 @@
package org.eehouse.android.xw4; package org.eehouse.android.xw4;
import android.graphics.Rect;
import android.app.Dialog; import android.app.Dialog;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
@ -39,8 +40,10 @@ import junit.framework.Assert;
public class FragActivity extends FragmentActivity public class FragActivity extends FragmentActivity
implements FragmentManager.OnBackStackChangedListener { implements FragmentManager.OnBackStackChangedListener {
private static final int MAX_PANES_LANDSCAPE = 2;
public interface OrientChangeListener { public interface OrientChangeListener {
void orientationChanged( int orientation ); void orientationChanged();
} }
private static FragActivity s_this; private static FragActivity s_this;
@ -79,17 +82,35 @@ public class FragActivity extends FragmentActivity
@Override @Override
public void onConfigurationChanged( Configuration newConfig ) public void onConfigurationChanged( Configuration newConfig )
{ {
int orientation = newConfig.orientation; Rect rect = new Rect();
boolean isPortrait = orientation == Configuration.ORIENTATION_PORTRAIT; m_root.getWindowVisibleDisplayFrame( rect );
int maxPanes = isPortrait? 1 : 2; // DbgUtils.logf( "FragActivity.onConfigurationChanged(): width=%d; height=%d",
// rect.width(), rect.height());
boolean isPortrait
= Configuration.ORIENTATION_PORTRAIT == newConfig.orientation;
if ( isPortrait != (rect.width() <= rect.height()) ) {
DbgUtils.logdf( "FragActivity.onConfigurationChanged(): isPortrait:"
+ " %b; width: %d; height: %d",
isPortrait, rect.width(), rect.height() );
}
int maxPanes = isPortrait? 1 : MAX_PANES_LANDSCAPE;
if ( m_maxPanes != maxPanes ) { if ( m_maxPanes != maxPanes ) {
m_maxPanes = maxPanes; m_maxPanes = maxPanes;
setVisiblePanes(); setVisiblePanes();
tellOrientationChanged( orientation );
} }
tellOrientationChanged();
super.onConfigurationChanged( newConfig ); super.onConfigurationChanged( newConfig );
} }
protected void getFragmentDims( int[] dims )
{
Rect rect = new Rect();
m_root.getWindowVisibleDisplayFrame( rect );
dims[0] = rect.width() / Math.min( m_maxPanes, m_root.getChildCount() );
dims[1] = rect.height();
}
@Override @Override
protected Dialog onCreateDialog( int id ) protected Dialog onCreateDialog( int id )
{ {
@ -225,7 +246,7 @@ public class FragActivity extends FragmentActivity
} }
// Walk all Fragment children and if they care notify of change. // Walk all Fragment children and if they care notify of change.
private void tellOrientationChanged( int orientation ) private void tellOrientationChanged()
{ {
FragmentManager fm = getSupportFragmentManager(); FragmentManager fm = getSupportFragmentManager();
int nPanes = m_root.getChildCount(); int nPanes = m_root.getChildCount();
@ -236,7 +257,7 @@ public class FragActivity extends FragmentActivity
if ( null == frag ) { if ( null == frag ) {
DbgUtils.logf( "tellOrienationChanged: NO FRAG at %d, id=%d", ii, id ); DbgUtils.logf( "tellOrienationChanged: NO FRAG at %d, id=%d", ii, id );
} else if ( frag instanceof OrientChangeListener ) { } else if ( frag instanceof OrientChangeListener ) {
((OrientChangeListener)frag).orientationChanged( orientation ); ((OrientChangeListener)frag).orientationChanged();
} }
} }
} }

View file

@ -28,7 +28,7 @@ import junit.framework.Assert;
// obtainable when other read locks are granted but not when a // obtainable when other read locks are granted but not when a
// write lock is. Write-locks are exclusive. // write lock is. Write-locks are exclusive.
public class GameLock { public class GameLock {
private static final boolean DEBUG_LOCKS = true; private static final boolean DEBUG_LOCKS = false;
private static final int SLEEP_TIME = 100; private static final int SLEEP_TIME = 100;
private static final long ASSERT_TIME = 2000; private static final long ASSERT_TIME = 2000;
private long m_rowid; private long m_rowid;

View file

@ -72,17 +72,12 @@ public class Toolbar {
private DlgDelegate.HasDlgDelegate m_dlgDlgt; private DlgDelegate.HasDlgDelegate m_dlgDlgt;
private LinearLayout m_layout; private LinearLayout m_layout;
private boolean m_visible; private boolean m_visible;
private Boolean m_isPortrait;
private enum ORIENTATION { ORIENT_PORTRAIT, ORIENT_LANDSCAPE }; public Toolbar( Activity activity, HasDlgDelegate dlgDlgt )
private ORIENTATION m_curOrient = null;
public Toolbar( Activity activity, HasDlgDelegate dlgDlgt,
boolean isLandscape )
{ {
m_activity = activity; m_activity = activity;
m_dlgDlgt = dlgDlgt; m_dlgDlgt = dlgDlgt;
setIsLandscape( isLandscape );
} }
public void setVisible( boolean visible ) public void setVisible( boolean visible )
@ -123,18 +118,10 @@ public class Toolbar {
setLongClickListener( index, listener ); setLongClickListener( index, listener );
} }
private void setIsLandscape( boolean landscape ) protected void setIsPortrait( boolean isPortrait )
{ {
if ( landscape && m_curOrient == ORIENTATION.ORIENT_LANDSCAPE ) { if ( null == m_isPortrait || m_isPortrait != isPortrait ) {
// do nothing m_isPortrait = isPortrait;
} else if ( !landscape && m_curOrient == ORIENTATION.ORIENT_PORTRAIT ) {
// do nothing
} else {
if ( landscape ) {
m_curOrient = ORIENTATION.ORIENT_LANDSCAPE;
} else {
m_curOrient = ORIENTATION.ORIENT_PORTRAIT;
}
doShowHide(); doShowHide();
} }
} }
@ -151,20 +138,21 @@ public class Toolbar {
private void doShowHide() private void doShowHide()
{ {
Assert.assertTrue( null != m_curOrient ); Assert.assertTrue( null != m_isPortrait );
boolean isLandscape = ORIENTATION.ORIENT_LANDSCAPE == m_curOrient;
if ( null == m_layout ) { if ( null == m_layout ) {
m_layout = (LinearLayout)LocUtils.inflate( m_activity, R.layout.toolbar ); m_layout = (LinearLayout)LocUtils.inflate( m_activity, R.layout.toolbar );
m_layout.setOrientation(ORIENTATION.ORIENT_PORTRAIT == m_curOrient } else {
? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL ); ((ViewGroup)m_layout.getParent()).removeView( m_layout );
}
m_layout.setOrientation( m_isPortrait ?
LinearLayout.HORIZONTAL : LinearLayout.VERTICAL );
int id = isLandscape ? R.id.tbar_parent_vert : R.id.tbar_parent_hor; int id = m_isPortrait ? R.id.tbar_parent_hor : R.id.tbar_parent_vert;
ViewGroup scroller = (ViewGroup)m_activity.findViewById( id ); ViewGroup scroller = (ViewGroup)m_activity.findViewById( id );
if ( null != scroller ) { if ( null != scroller ) {
// Google's had reports of a crash adding second view // Google's had reports of a crash adding second view
scroller.removeAllViews(); scroller.removeAllViews();
scroller.addView( m_layout ); // failing scroller.addView( m_layout );
}
} }
m_layout.setVisibility( m_visible? View.VISIBLE : View.GONE ); m_layout.setVisibility( m_visible? View.VISIBLE : View.GONE );

View file

@ -22,6 +22,7 @@ package org.eehouse.android.xw4;
import android.app.Activity; import android.app.Activity;
import android.app.Dialog; import android.app.Dialog;
import android.content.Intent; import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
import android.view.ContextMenu.ContextMenuInfo; import android.view.ContextMenu.ContextMenuInfo;
import android.view.ContextMenu; import android.view.ContextMenu;
@ -178,6 +179,13 @@ public class XWActivity extends Activity implements Delegator {
m_dlgt.prepareDialog( DlgID.values()[id], dialog ); m_dlgt.prepareDialog( DlgID.values()[id], dialog );
} }
@Override
public void onConfigurationChanged( Configuration newConfig )
{
m_dlgt.orientationChanged();
super.onConfigurationChanged( newConfig );
}
@Override @Override
protected void onActivityResult( int requestCode, int resultCode, protected void onActivityResult( int requestCode, int resultCode,
Intent data ) Intent data )

View file

@ -20,6 +20,7 @@
package org.eehouse.android.xw4; package org.eehouse.android.xw4;
import android.content.res.Configuration;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -33,7 +34,9 @@ import android.widget.ListView;
import junit.framework.Assert; import junit.framework.Assert;
public class XWFragment extends Fragment implements Delegator { public class XWFragment extends Fragment
implements Delegator,
FragActivity.OrientChangeListener {
private DelegateBase m_dlgt; private DelegateBase m_dlgt;
@ -122,6 +125,12 @@ public class XWFragment extends Fragment implements Delegator {
Assert.fail(); Assert.fail();
} }
// FragActivity.OrientChangeListener
public void orientationChanged()
{
m_dlgt.orientationChanged();
}
public ListView getListView() public ListView getListView()
{ {
ListView view = (ListView)m_dlgt.findViewById( android.R.id.list ); ListView view = (ListView)m_dlgt.findViewById( android.R.id.list );