Okay, I have it working the way I want. I'm posting my changes here in case it helps someone else, or in case you'd want to integrate this into the product. Rather than modifying dev_view=6, I created a new def_view=100 to avoid conflicts with future versions.
Class: PDFLayoutView
Method: PDFSetView
Line in method: 38
Add this case statement:
case 100: {
	// arlo added: don't let the first page appear alone in either orientation
	PDFLayoutDual layout = new PDFLayoutDual(getContext());
	boolean paras[] = new boolean[m_doc.GetPageCount()];
	int cur = 0;
	while (cur < paras.length) {
		paras[cur] = true;
		cur++;
	}
	layout.vSetLayoutPara(paras, paras, Global.rtol, false);
	m_layout = layout;
} PDFViewDual
Method: vOnFling
Line in method: 8
Change "Global.def_view == 6" to "(Global.def_view == 6 || Global.def_view == 100)"
Class: PDFLayoutDual
Method: (class definition)
Line in method: 9
Add these two lines to the forward class declaration for PDFCell:
public int top;
public int bottom;
 PDFLayoutDual
Method: vLayout
Line in method: 11
Replace "if( m_h > m_w )" with "if ((Global.def_view != 100)&&( m_h > m_w ))" because I want to always use two columns, even with a portrait-oriented viewer.
Then go to the "else" section of that condition and replace the entire block with:
while( pcur < pcnt )
{
	// arlo comment: this section gets the width and height of each pair of pages
	if( (m_horz_dual == null || ccnt >= m_horz_dual.length/* || m_horz_dual[ccnt]*/) && pcur == 0 )
	{
		// arlo comment: first page if it appears alone; we're avoiding this by setting horzs in vSetLayoutPara
		float w = m_doc.GetPageWidth(pcur);
		if( max_w < w ) max_w = w;
		float h = m_doc.GetPageHeight(pcur);
		if( max_h < h ) max_h = h;
		if(Global.fit_different_page_size && m_scales[pcur] == 0) {
			m_scales[pcur] = ((float)(m_h - m_page_gap)) / h;
			m_scales_min[pcur] = ((float)(m_h - m_page_gap)) / h;
		}
		pcur++;
	}
	else
	if( (m_horz_dual == null || ccnt >= m_horz_dual.length || m_horz_dual[ccnt]) && pcur < pcnt - 1 )
	{
		// arlo comment: pairs of pages
		float w = m_doc.GetPageWidth(pcur) + m_doc.GetPageWidth(pcur + 1);
		if( max_w < w ) max_w = w;
		float h = m_doc.GetPageHeight(pcur);
		if( max_h < h ) max_h = h;
		h = m_doc.GetPageHeight(pcur + 1);
		if( max_h < h ) max_h = h;
		if(Global.fit_different_page_size && m_scales[pcur] == 0) {
			float minScale = (m_w - m_page_gap) / w;
			float scale = ((float)(m_h - m_page_gap)) / m_doc.GetPageHeight(pcur);
			if( minScale > scale ) minScale = scale;
			m_scales[pcur] = minScale;
			m_scales_min[pcur] = minScale;
			scale = ((float)(m_h - m_page_gap)) / m_doc.GetPageHeight(pcur + 1);
			if( minScale > scale ) minScale = scale;
			m_scales[pcur + 1] = minScale;
			m_scales_min[pcur + 1] = minScale;
		}
		pcur += 2;
	}
	else
	{
		// arlo comment: last page if it appears alone
		float w = m_doc.GetPageWidth(pcur);
		if( max_w < w ) max_w = w;
		float h = m_doc.GetPageHeight(pcur);
		if( max_h < h ) max_h = h;
		if(Global.fit_different_page_size && m_scales[pcur] == 0) {
			m_scales[pcur] = ((float)(m_h - m_page_gap)) / h;
			m_scales_min[pcur] = ((float)(m_h - m_page_gap)) / h;
		}
		pcur++;
	}
	ccnt++;
}
m_scale_min = ((float) (m_w - m_page_gap)) / max_w;
if (Global.def_view != 100) {
	// arlo removed: don't fit to height because I'm handling that outside the viewer; other people will probably want to leave this as it was
	float scale = ((float)(m_h - m_page_gap)) / max_h;
	if( m_scale_min > scale ) m_scale_min = scale;
}
m_scale_max = m_scale_min * m_zoom_level;
if( m_scale < m_scale_min ) m_scale = m_scale_min;
if( m_scale > m_scale_max ) m_scale = m_scale_max;
boolean clip = m_scale / m_scale_min > m_zoom_level_clip;
if (Global.def_view == 100) {
	// arlo added: set the total size of the static dimension
	m_tw = Global.fit_different_page_size && vGetScale() == vGetMinScale() ? m_w : (int) (max_w * m_scale) + m_page_gap;
} else {
	m_th = Global.fit_different_page_size && vGetScale() == vGetMinScale() ? m_h : (int) (max_h * m_scale) + m_page_gap;
}
if (m_th < m_h) m_th = m_h;
m_cells = new PDFCell[ccnt];
pcur = 0;
ccur = 0;
int left = 0;
int top = 0; // arlo added
while( ccur < ccnt )
{
	PDFCell cell = new PDFCell();
	int w = 0;
	int h = 0;
	int cw = 0;
	int ch = 0;
	boolean clipPage = Global.fit_different_page_size ? m_scales[pcur] / m_scales_min[pcur] > m_zoom_level_clip : clip;
	float pageScale = Global.fit_different_page_size ? m_scales[pcur] : m_scale;
	if ((m_horz_dual == null || ccur >= m_horz_dual.length ) && pcur == 0 )
	{
		// arlo comment: position the first page if it appears alone; we're avoiding this by setting horzs in vSetLayoutPara
		w = (int)( m_doc.GetPageWidth(pcur) * pageScale );
		h = (int)( m_doc.GetPageHeight(pcur) * pageScale );
		if( w + m_page_gap < m_w ) cw = m_w;
		else cw = w + m_page_gap;
		if( h + m_page_gap < m_h ) ch = m_h;
		else ch = h + m_page_gap;
		cell.page_left = pcur;
		cell.page_right = -1;
		cell.left = left;
		cell.right = left + cw;
		cell.top = top; // arlo added
		cell.bottom = top + ch; // arlo added
		if(m_page_align_top)
		{
			m_pages[pcur].vLayout(left + (cw - w) / 2, m_page_gap / 2, pageScale, clipPage);
		}
		else {
			if (Global.def_view == 100) {
				// arlo added
				m_pages[pcur].vLayout(left + (cw - w) / 2, top + (ch - h) / 2, pageScale, clipPage);
			} else {
				m_pages[pcur].vLayout(left + (cw - w) / 2, (int) (m_th - m_doc.GetPageHeight(pcur) * pageScale) / 2, pageScale, clipPage);
			}
		}
		pcur++;
	}
	else if( (m_horz_dual == null || ccur >= m_horz_dual.length || m_horz_dual[ccur]) && pcur < pcnt - 1 )
	{
		// arlo comment: position pairs of pages
		float pageScale2 = Global.fit_different_page_size ? m_scales[pcur + 1] : m_scale;
		w = Global.fit_different_page_size ? (int)( (m_doc.GetPageWidth(pcur) * pageScale) + (m_doc.GetPageWidth(pcur + 1)
				* pageScale2)) : (int)( (m_doc.GetPageWidth(pcur) + m_doc.GetPageWidth(pcur + 1)) * pageScale);
		h = Global.fit_different_page_size ? (int)( Math.max((m_doc.GetPageHeight(pcur) * pageScale), (m_doc.GetPageHeight(pcur + 1)
				* pageScale2)) ) : (int)( Math.max((m_doc.GetPageHeight(pcur) * pageScale), (m_doc.GetPageHeight(pcur + 1) * pageScale)) );
		if( w + m_page_gap < m_w ) cw = m_w;
		else cw = w + m_page_gap;
		if( h + m_page_gap < m_h ) ch = m_h;
		else ch = h + m_page_gap;
		cell.page_left = pcur;
		cell.page_right = pcur + 1;
		cell.left = left + 10; // I have no idea why, but without the +10 here, only the middle cell appears
		cell.right = left + cw - 10; // ditto
		cell.top = top; // arlo added
		cell.bottom = top + ch; // arlo added
		if(m_page_align_top)
		{
			m_pages[pcur].vLayout(left + (cw - w) / 2, m_page_gap / 2, pageScale, clip);
			m_pages[pcur + 1].vLayout(m_pages[pcur].GetX() + m_pages[pcur].GetWidth(), m_page_gap / 2, pageScale2, clip);
		}
		else {
			if (Global.def_view == 100) {
				// arlo added
				m_pages[pcur].vLayout(left + (cw - w) / 2, top + (ch - h) / 2, pageScale, clip);
				m_pages[pcur + 1].vLayout(m_pages[pcur].GetX() + m_pages[pcur].GetWidth(), top + (ch - h) / 2, pageScale2, clip);
			} else {
				m_pages[pcur].vLayout(left + (cw - w) / 2, (int) (m_th - m_doc.GetPageHeight(pcur) * pageScale) / 2, pageScale, clip);
				m_pages[pcur + 1].vLayout(m_pages[pcur].GetX() + m_pages[pcur].GetWidth(), (int) (m_th - m_doc.GetPageHeight(pcur + 1) * pageScale2) / 2, pageScale2, clip);
			}
		}
		pcur += 2;
	}
	else
	{
		// arlo comment: position the last page if it appears alone
		w = (int)( m_doc.GetPageWidth(pcur) * pageScale );
		h = (int)( m_doc.GetPageHeight(pcur) * pageScale );
		if( w + m_page_gap < m_w ) cw = m_w;
		else cw = w + m_page_gap;
		if( h + m_page_gap < m_h ) ch = m_h;
		else ch = h + m_page_gap;
		cell.page_left = pcur;
		cell.page_right = -1;
		cell.left = left;
		cell.right = left + cw;
		cell.top = top; // arlo added
		cell.bottom = top + ch; // arlo added
		if(m_page_align_top)
		{
			m_pages[pcur].vLayout(left + (cw - w) / 2, m_page_gap / 2, pageScale, clipPage);
		}
		else {
			if (Global.def_view == 100) {
				// arlo added
				m_pages[pcur].vLayout(left + (cw - w) / 2, top + (ch - h) / 2, pageScale, clipPage);
			} else {
				m_pages[pcur].vLayout(left + (cw - w) / 2, (int) (m_th - m_doc.GetPageHeight(pcur) * pageScale) / 2, pageScale, clipPage);
			}
		}
		pcur++;
	}
	if (Global.def_view == 100) {
		// arlo added
		top += ch;
	} else {
		left += cw;
	}
	m_cells[ccur] = cell;
	ccur++;
}
if (Global.def_view == 100) {
	// arlo added: set the total size of the scrolling dimension
	m_th = top;
} else {
	m_tw = left;
}
Here's a screen recording showing how it works: