diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 000000000..0dab7d096 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,40 @@ +language: android +jdk: oraclejdk8 +env: + global: + - ANDROID_TARGET=android-15 + - ANDROID_ABI=armeabi-v7a,x86 + - secure: d8PwteM+xp1IRU3QkvmHtxh+1Ta9n/kl/SJ3EZa3iColVVXY1etzjY3cKrEGKKMJuI4be30kPzvNw9/BVTawDpnU9/NtWqykJ8QHXNWnZIvUQ/kxHBS1DbcstmcYU9gvR83EFb8BT+Y9frpNfMcZDlSvBpEGqDQEPmxiDzSmjdUmJJQWStncxL9pE+lCdM6lHBgtfYoMMiqCQF/DxkQisjyUVF4mbTGuT9JOOWjVsTGPA7ehzsWDHoJ3p2ai8UKHAYucUWZcTt4rkq9l35ExvgKd3L8luk8U3X3Fk9yzVhPJC56T0XNbNrsQ2W7/7oGRv6EQFV3aKDZimJ7CVjBcEjZmPxeUVvCsMW8XB41ZvYcy6xsjF96oyjn1gb0r/2mZbTaWP0izSTwMYZ5vFNKUamDtRZgrneD0lfvXgfTzirrCU7FqO2RH7ZK5PQpSgSoZxKsKyeyFPEa2ihivc95rz1MS6mamle9wrIlSAgEGcaZMIYvKiOnCLk7CZCKuwm2dhYPgzCHW3PUopay59BBwMsSqWpxsiHEr5jYGpb0pHGbzPTJNUpg1LNQX5eMQOMlEt7rfpoC7JG24hR9vxl4Yf9LhxYlSwUiPy7TYHdbA0kUS68skfzxU6+ekWZF2QFM+L4vWCYmEHDy7n+I0df+PavycgNW989ROlAKhQjtMyqM= +android: + components: + - tools + - platform-tools + - build-tools-23.0.3 + - android-23 +before_script: +- export TERM=dumb +- curl -L http://dl.google.com/android/ndk/android-ndk-r10e-linux-x86_64.bin -O +- chmod u+x android-ndk-r10e-linux-x86_64.bin +- "./android-ndk-r10e-linux-x86_64.bin > /dev/null" +- rm android-ndk-r10e-linux-x86_64.bin +- export ANDROID_NDK_HOME=`pwd`/android-ndk-r10e +- export LOCAL_ANDROID_NDK_HOME="$ANDROID_NDK_HOME" +- export LOCAL_ANDROID_NDK_HOST_PLATFORM="linux-x86_64" +- export PATH=$PATH:${ANDROID_NDK_HOME} +- cd xwords4/android/ +before_install: +- openssl aes-256-cbc -K $encrypted_8436f2891714_key -iv $encrypted_8436f2891714_iv + -in id_rsa_uploader.enc -out /tmp/id_rsa_uploader -d +- chmod 600 \/tmp\/id_rsa_uploader +- sudo apt-get -qq update +- sudo apt-get install -y python-lxml imagemagick +script: +- "./gradlew -PuseCrashlytics assXw4dDeb" +- scp -o "StrictHostKeyChecking no" -i /tmp/id_rsa_uploader -d app/build/outputs/apk/*.apk + uploader@eehouse.org:XW4D_UPLOAD +notifications: + email: + recipients: + - xwords@eehouse.org + on_success: always + on_failure: always diff --git a/id_rsa_uploader.enc b/id_rsa_uploader.enc new file mode 100644 index 000000000..16e5dd866 Binary files /dev/null and b/id_rsa_uploader.enc differ diff --git a/xwords4/android/app/build.gradle b/xwords4/android/app/build.gradle index 62d5771a4..563cce10e 100644 --- a/xwords4/android/app/build.gradle +++ b/xwords4/android/app/build.gradle @@ -1,7 +1,9 @@ def INITIAL_CLIENT_VERS = 8 -def VERSION_CODE_BASE = 121 -def VERSION_NAME = '4.4.125' +def VERSION_CODE_BASE = 126 +def VERSION_NAME = '4.4.130' def FABRIC_API_KEY = System.getenv("FABRIC_API_KEY") +def GCM_SENDER_ID = System.getenv("GCM_SENDER_ID") +def BUILD_INFO_NAME = "build-info.txt" boolean forFDroid = hasProperty('forFDroid') @@ -37,8 +39,6 @@ android { applicationVariants.all { variant -> // renameArtifact(variant) // variant.buildConfigField "String", "FIELD_NAME", "\"my String\"" - def GCM_SENDER_ID = System.getenv("GCM_SENDER_ID") - variant.buildConfigField "String", "SENDER_ID", "\"$GCM_SENDER_ID\"" variant.buildConfigField "String", "FABRIC_API_KEY", "\"$FABRIC_API_KEY\"" resValue "string", "git_rev", "$GITREV" @@ -51,9 +51,6 @@ android { // FIX ME variant.buildConfigField "String", "STRINGS_HASH", "\"00000\"" - def senderID = System.getenv("GCM_SENDER_ID") - variant.buildConfigField "String", "GCM_SENDER_ID", "\"$senderID\"" - variant.buildConfigField "short", "CLIENT_VERS_RELAY", "$INITIAL_CLIENT_VERS" variant.buildConfigField "boolean", "FOR_FDROID", "$forFDroid" @@ -61,6 +58,10 @@ android { flavorDimensions "variant"//, "abi" productFlavors { + all { + buildConfigField "String", "BUILD_INFO_NAME", "\"${BUILD_INFO_NAME}\"" + } + xw4 { dimension "variant" applicationId "org.eehouse.android.xw4" @@ -70,6 +71,8 @@ android { resValue "string", "invite_prefix", "/and/" buildConfigField "boolean", "WIDIR_ENABLED", "false" buildConfigField "boolean", "RELAYINVITE_SUPPORTED", "false" + + buildConfigField "String", "GCM_SENDER_ID", "\"$GCM_SENDER_ID\"" } xw4d { dimension "variant" @@ -81,6 +84,8 @@ android { resValue "string", "invite_prefix", "/anddbg/" buildConfigField "boolean", "WIDIR_ENABLED", "true" buildConfigField "boolean", "RELAYINVITE_SUPPORTED", "true" + + buildConfigField "String", "GCM_SENDER_ID", "\"\"" } // WARNING: "all" breaks things. Seems to be a keyword. Need @@ -254,9 +259,14 @@ afterEvaluate { task makeBuildAssets() { def assetsDir = android.sourceSets.main.assets.srcDirs.toArray()[0] - String path = new File(assetsDir, 'build-info.txt').getAbsolutePath() - File file = new File(path); - file.write("git: ${GITREV}\n"); + String path = new File(assetsDir, BUILD_INFO_NAME).getAbsolutePath() + String out = "git: ${GITREV}\n" + + String diff = "git diff".execute().text.trim() + if (diff) { + out += "\n" + diff + } + new File(path).write(out) } gradle.projectsEvaluated { diff --git a/xwords4/android/app/src/main/AndroidManifest.xml b/xwords4/android/app/src/main/AndroidManifest.xml index bc49a4b99..6fa3ddb0f 100644 --- a/xwords4/android/app/src/main/AndroidManifest.xml +++ b/xwords4/android/app/src/main/AndroidManifest.xml @@ -34,13 +34,7 @@ /> - - - - - - - - - - - - - - - diff --git a/xwords4/android/app/src/main/assets/changes.html b/xwords4/android/app/src/main/assets/changes.html index 87690a560..09d30d22e 100644 --- a/xwords4/android/app/src/main/assets/changes.html +++ b/xwords4/android/app/src/main/assets/changes.html @@ -13,10 +13,9 @@ -

CrossWords 4.4.125 release

+

CrossWords 4.4.130 release

-

This release fixes a problem inviting to new networked games, and - with title bars on some Samsung devices.

+

This release makes a couple of small UI tweaks.

Please take @@ -26,10 +25,12 @@

New with this release

    -
  • Fix delays bringing up the Invite dialog for new games
  • -
  • Explicitly specify application "theme" to fix a Samsung - "upgrade" turning the titlebar white and so making menu - icons disappear
  • +
  • Offer to "Archive" finished games
  • +
  • Make tap on thumbnail toggle whether game's selected rather + than open it. (Tap to the right still opens)
  • +
  • Bug fix: don't allow duplicate group names
  • +
  • Fix battery-hogging behavior on non-Google-play + installs

(The full changelog diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BTService.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BTService.java index 70df610ca..1fb0a9c3f 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BTService.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BTService.java @@ -550,7 +550,7 @@ public class BTService extends XWService { } else { short len = is.readShort(); byte[] nliData = new byte[len]; - is.read( nliData ); + is.readFully( nliData ); nli = XwJNI.nliFromStream( nliData ); } @@ -573,26 +573,20 @@ public class BTService extends XWService { int gameID = dis.readInt(); switch ( cmd ) { case MESG_SEND: - short len = dis.readShort(); - byte[] buffer = new byte[len]; - int nRead = dis.read( buffer, 0, len ); - if ( nRead == len ) { - BluetoothDevice host = socket.getRemoteDevice(); - addAddr( host ); + byte[] buffer = new byte[dis.readShort()]; + dis.readFully( buffer ); + BluetoothDevice host = socket.getRemoteDevice(); + addAddr( host ); - CommsAddrRec addr = new CommsAddrRec( host.getName(), - host.getAddress() ); - ReceiveResult rslt - = BTService.this.receiveMessage( BTService.this, - gameID, m_btMsgSink, - buffer, addr ); + CommsAddrRec addr = new CommsAddrRec( host.getName(), + host.getAddress() ); + ReceiveResult rslt + = BTService.this.receiveMessage( BTService.this, + gameID, m_btMsgSink, + buffer, addr ); - result = rslt == ReceiveResult.GAME_GONE ? - BTCmd.MESG_GAMEGONE : BTCmd.MESG_ACCPT; - } else { - Log.e( TAG, "receiveMessage(): read only %d of %d bytes", - nRead, len ); - } + result = rslt == ReceiveResult.GAME_GONE ? + BTCmd.MESG_GAMEGONE : BTCmd.MESG_ACCPT; break; case MESG_GAMEGONE: postEvent( MultiEvent.MESSAGE_NOGAME, gameID ); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BiDiSockWrap.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BiDiSockWrap.java index 9b97432d5..e2744c9f5 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BiDiSockWrap.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BiDiSockWrap.java @@ -188,10 +188,8 @@ public class BiDiSockWrap { DataInputStream inStream = new DataInputStream( mSocket.getInputStream() ); while ( mRunThreads ) { - short len = inStream.readShort(); - Log.d( TAG, "got len: %d", len ); - byte[] packet = new byte[len]; - inStream.read( packet ); + byte[] packet = new byte[inStream.readShort()]; + inStream.readFully( packet ); mIface.gotPacket( BiDiSockWrap.this, packet ); } } catch( IOException ioe ) { diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardCanvas.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardCanvas.java index 176f6d7cc..5b0dcd7a3 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardCanvas.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardCanvas.java @@ -322,26 +322,35 @@ public class BoardCanvas extends Canvas implements DrawCtx { } } - public void drawTimer( Rect rect, int player, int secondsLeft ) + public void drawTimer( Rect rect, final int player, + int secondsLeft ) { - if ( null != m_jniThread && - (m_lastSecsLeft != secondsLeft || m_lastTimerPlayer != player) ) { - m_lastSecsLeft = secondsLeft; - m_lastTimerPlayer = player; + if ( m_lastSecsLeft != secondsLeft || m_lastTimerPlayer != player ) { + final Rect rectCopy = new Rect(rect); + final int secondsLeftCopy = secondsLeft; + m_activity.runOnUiThread( new Runnable() { + @Override + public void run() { + if ( null != m_jniThread ) { + m_lastSecsLeft = secondsLeftCopy; + m_lastTimerPlayer = player; - String negSign = secondsLeft < 0? "-":""; - secondsLeft = Math.abs( secondsLeft ); - String time = String.format( "%s%d:%02d", negSign, secondsLeft/60, - secondsLeft%60 ); + String negSign = secondsLeftCopy < 0? "-":""; + int secondsLeft = Math.abs( secondsLeftCopy ); + String time = + String.format( "%s%d:%02d", negSign, + secondsLeft/60, secondsLeft%60 ); - fillRectOther( rect, CommonPrefs.COLOR_BACKGRND ); - m_fillPaint.setColor( m_playerColors[player] ); + fillRectOther( rectCopy, CommonPrefs.COLOR_BACKGRND ); + m_fillPaint.setColor( m_playerColors[player] ); - Rect shorter = new Rect( rect ); - shorter.inset( 0, shorter.height() / 5 ); - drawCentered( time, shorter, null ); + rectCopy.inset( 0, rectCopy.height() / 5 ); + drawCentered( time, rectCopy, null ); - m_jniThread.handle( JNIThread.JNICmd.CMD_DRAW ); + m_jniThread.handle( JNIThread.JNICmd.CMD_DRAW ); + } + } + } ); } } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java index 78e963232..b90febc40 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardDelegate.java @@ -104,7 +104,6 @@ public class BoardDelegate extends DelegateBase private Button m_exchCancelButton; private SentInvitesInfo m_sentInfo; private Perms23.PermCbck m_permCbck; - private ArrayList m_pendingChats; private CommsConnTypeSet m_connTypes = null; private String[] m_missingDevs; @@ -205,6 +204,25 @@ public class BoardDelegate extends DelegateBase } }; ab.setNegativeButton( R.string.button_rematch, lstnr ); + + // If we're not already in the "archive" group, offer to move + final String archiveName = LocUtils + .getString( m_activity, R.string.group_name_archive ); + final long archiveGroup = DBUtils.getGroup( m_activity, archiveName ); + long curGroup = DBUtils.getGroupForGame( m_activity, m_rowid ); + if ( curGroup != archiveGroup ) { + lstnr = new OnClickListener() { + public void onClick( DialogInterface dlg, + int whichButton ) { + makeNotAgainBuilder( R.string.not_again_archive, + R.string.key_na_archive, + Action.ARCHIVE_ACTION ) + .setParams( archiveName, archiveGroup ) + .show(); + } + }; + ab.setNeutralButton( R.string.button_archive, lstnr ); + } } else if ( DlgID.DLG_CONNSTAT == dlgID && BuildConfig.DEBUG && null != m_connTypes && (m_connTypes.contains( CommsConnType.COMMS_CONN_RELAY ) @@ -553,8 +571,6 @@ public class BoardDelegate extends DelegateBase m_isFirstLaunch = null == savedInstanceState; getBundledData( savedInstanceState ); - m_pendingChats = new ArrayList(); - m_utils = new BoardUtilCtxt(); m_timers = new TimerRunnable[4]; // needs to be in sync with // XWTimerReason @@ -843,7 +859,7 @@ public class BoardDelegate extends DelegateBase Utils.setItemVisible( menu, R.id.board_menu_game_invites, enable ); enable = XWPrefs.getStudyEnabled( m_activity ); - Utils.setItemVisible( menu, R.id.games_menu_study, enable ); + Utils.setItemVisible( menu, R.id.board_menu_study, enable ); return true; } // onPrepareOptionsMenu @@ -913,7 +929,7 @@ public class BoardDelegate extends DelegateBase case R.id.board_menu_tray: cmd = JNICmd.CMD_TOGGLE_TRAY; break; - case R.id.games_menu_study: + case R.id.board_menu_study: StudyListDelegate.launchOrAlert( getDelegator(), m_gi.dictLang, this ); break; case R.id.board_menu_game_netstats: @@ -1095,6 +1111,12 @@ public class BoardDelegate extends DelegateBase makeOkOnlyBuilder( R.string.after_restart ).show(); break; + case ARCHIVE_ACTION: + String archiveName = (String)params[0]; + long archiveGroup = (Long)params[1]; + archiveAndClose( archiveName, archiveGroup ); + break; + case ENABLE_SMS_DO: post( new Runnable() { public void run() { @@ -2144,7 +2166,6 @@ public class BoardDelegate extends DelegateBase if ( m_gi.serverRole != DeviceRole.SERVER_STANDALONE ) { warnIfNoTransport(); - trySendChats(); tickle( isStart ); tryInvites(); } @@ -2407,15 +2428,6 @@ public class BoardDelegate extends DelegateBase } } - private void trySendChats() - { - Iterator iter = m_pendingChats.iterator(); - while ( iter.hasNext() ) { - handleViaThread( JNICmd.CMD_SENDCHAT, iter.next() ); - } - m_pendingChats.clear(); - } - private void tryInvites() { if ( 0 < m_mySIS.nMissing && m_summary.hasRematchInfo() ) { @@ -2588,6 +2600,16 @@ public class BoardDelegate extends DelegateBase return wordsArray; } + private void archiveAndClose( String archiveName, long groupID ) + { + if ( DBUtils.GROUPID_UNSPEC == groupID ) { + groupID = DBUtils.addGroup( m_activity, archiveName ); + } + DBUtils.moveGame( m_activity, m_rowid, groupID ); + waitCloseGame( false ); + finish(); + } + // For now, supported if standalone or either BT or SMS used for transport private boolean rematchSupported( boolean showMulti ) { diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardView.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardView.java index 25b804311..d0c9f33de 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardView.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/BoardView.java @@ -158,8 +158,7 @@ public class BoardView extends View implements BoardHandler, SyncedDraw { if ( null != m_dims ) { if ( BoardContainer.getIsPortrait() != (m_dims.height > m_dims.width) ) { - // square possible; will break above! - Assert.assertTrue( m_dims.height != m_dims.width ); + // square possible; will break above! No. tested by forceing square Log.d( TAG, "onMeasure: discarding m_dims" ); if ( ++m_dimsTossCount < 4 ) { m_dims = null; diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ConnStatusHandler.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ConnStatusHandler.java index c2d0b9795..3a544a429 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ConnStatusHandler.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ConnStatusHandler.java @@ -52,9 +52,6 @@ public class ConnStatusHandler { public Handler getHandler(); } - private static final int GREEN = 0xFF00AF00; - private static final int RED = 0xFFAF0000; - private static final int BLACK = 0xFF000000; private static final int SUCCESS_IN = 0; private static final int SUCCESS_OUT = 1; private static final int SHOW_SUCCESS_INTERVAL = 1000; @@ -340,7 +337,7 @@ public class ConnStatusHandler { boolean isIn ) { enabled = enabled && null != newestSuccess( connTypes, isIn ); - s_fillPaint.setColor( enabled ? GREEN : RED ); + s_fillPaint.setColor( enabled ? XWApp.GREEN : XWApp.RED ); canvas.drawRect( rect, s_fillPaint ); } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java index 5ac2fc34c..9f287b36b 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DBUtils.java @@ -81,7 +81,9 @@ public class DBUtils { private static long s_cachedRowID = ROWID_NOTFOUND; private static byte[] s_cachedBytes = null; - public static enum GameChangeType { GAME_CHANGED, GAME_CREATED, GAME_DELETED }; + public static enum GameChangeType { GAME_CHANGED, GAME_CREATED, + GAME_DELETED, GAME_MOVED, + }; public static interface DBChangeListener { public void gameSaved( long rowid, GameChangeType change ); @@ -1616,21 +1618,34 @@ public class DBUtils { return result; } + // ORDER BY clause that governs display of games in main GamesList view + private static final String s_getGroupGamesOrderBy = + TextUtils.join(",", new String[] { + // Ended games at bottom + DBHelper.GAME_OVER, + // games with unread chat messages at top + "(" + DBHelper.HASMSGS + " & " + GameSummary.MSG_FLAGS_CHAT + ") IS NOT 0 DESC", + // Games not yet connected at top + DBHelper.TURN + " is -1 DESC", + // Games where it's a local player's turn at top + DBHelper.TURN_LOCAL + " DESC", + // finally, sort by timestamp of last-made move + DBHelper.LASTMOVE, + }); + public static long[] getGroupGames( Context context, long groupID ) { long[] result = null; initDB( context ); - String[] columns = { ROW_ID }; + String[] columns = { ROW_ID, DBHelper.HASMSGS }; String selection = String.format( "%s=%d", DBHelper.GROUPID, groupID ); - String orderBy = String.format( "%s,%s DESC,%s", DBHelper.GAME_OVER, - DBHelper.TURN_LOCAL, DBHelper.LASTMOVE ); synchronized( s_dbHelper ) { Cursor cursor = s_db.query( DBHelper.TABLE_NAME_SUM, columns, selection, // selection null, // args null, // groupBy null, // having - orderBy + s_getGroupGamesOrderBy ); int index = cursor.getColumnIndex( ROW_ID ); result = new long[ cursor.getCount() ]; @@ -1688,6 +1703,29 @@ public class DBUtils { return result; } + public static long getGroup( Context context, String name ) + { + long result = GROUPID_UNSPEC; + String[] columns = { ROW_ID }; + String selection = DBHelper.GROUPNAME + " = ?"; + String[] selArgs = { name }; + + initDB( context ); + synchronized( s_dbHelper ) { + Cursor cursor = s_db.query( DBHelper.TABLE_NAME_GROUPS, columns, + selection, selArgs, + null, // groupBy + null, // having + null // orderby + ); + if ( cursor.moveToNext() ) { + result = cursor.getLong( cursor.getColumnIndex( ROW_ID ) ); + } + cursor.close(); + } + return result; + } + public static long addGroup( Context context, String name ) { long rowid = GROUPID_UNSPEC; @@ -1746,13 +1784,14 @@ public class DBUtils { } // Change group id of a game - public static void moveGame( Context context, long gameid, long groupID ) + public static void moveGame( Context context, long rowid, long groupID ) { Assert.assertTrue( GROUPID_UNSPEC != groupID ); ContentValues values = new ContentValues(); values.put( DBHelper.GROUPID, groupID ); - updateRow( context, DBHelper.TABLE_NAME_SUM, gameid, values ); + updateRow( context, DBHelper.TABLE_NAME_SUM, rowid, values ); invalGroupsCache(); + notifyListeners( rowid, GameChangeType.GAME_MOVED ); } private static String getChatHistoryStr( Context context, long rowid ) diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DelegateBase.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DelegateBase.java index 5b9f4da1b..144c61b91 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DelegateBase.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DelegateBase.java @@ -163,6 +163,7 @@ public class DelegateBase implements DlgClickNotify, } if ( this != result ) { Log.d( TAG, "%s.curThis() => " + result, this.toString() ); + Assert.fail(); } return result; } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java index 265e4b7d6..8b13e3b91 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/DlgDelegate.java @@ -84,6 +84,7 @@ public class DlgDelegate { TRAY_PICKED, INVITE_INFO, DISABLE_DUALPANE, + ARCHIVE_ACTION, // Dict Browser FINISH_ACTION, diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ExpiringDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ExpiringDelegate.java index 72607dfb1..3987291eb 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ExpiringDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/ExpiringDelegate.java @@ -22,7 +22,6 @@ package org.eehouse.android.xw4; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; @@ -214,13 +213,13 @@ public class ExpiringDelegate { int offset = 0; int count = s_points.length; if ( 0 < redWidth ) { - s_paint.setColor( Color.RED ); + s_paint.setColor( XWApp.RED ); canvas.drawLines( s_points, offset, count / 2, s_paint ); count /= 2; offset += count; } if ( redWidth < width ) { - s_paint.setColor( Color.GREEN ); + s_paint.setColor( XWApp.GREEN ); } canvas.drawLines( s_points, offset, count, s_paint ); } @@ -256,7 +255,7 @@ public class ExpiringDelegate { Paint paint = new Paint(); paint.setStyle(Paint.Style.FILL); - paint.setColor( Color.RED ); + paint.setColor( XWApp.RED ); canvas.drawRect( 0, 0, pct, 1, paint ); paint.setColor( Utils.TURN_COLOR ); canvas.drawRect( pct, 0, 100, 1, paint ); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameListItem.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameListItem.java index efeeaa513..f3cd41e91 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameListItem.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameListItem.java @@ -64,7 +64,7 @@ public class GameListItem extends LinearLayout private LinearLayout m_list; private TextView m_state; private TextView m_modTime; - private ImageView m_marker; + private ImageView m_gameTypeImage; private TextView m_role; private boolean m_expanded, m_haveTurn, m_haveTurnLocal; @@ -90,16 +90,6 @@ public class GameListItem extends LinearLayout m_lastMoveTime = 0; m_loadingCount = 0; m_dsdel = new DrawSelDelegate( this ); - - setOnClickListener( new View.OnClickListener() { - @Override - public void onClick( View v ) { - // if selected, just un-select - if ( null != m_summary ) { - m_cb.itemClicked( GameListItem.this, m_summary ); - } - } - } ); } public GameSummary getSummary() @@ -174,13 +164,32 @@ public class GameListItem extends LinearLayout } // View.OnClickListener interface - public void onClick( View view ) { - m_expanded = !m_expanded; - DBUtils.setExpanded( m_rowid, m_expanded ); + public void onClick( View view ) + { + int id = view.getId(); + switch ( id ) { + case R.id.expander: + m_expanded = !m_expanded; + DBUtils.setExpanded( m_rowid, m_expanded ); - makeThumbnailIf( m_expanded ); + makeThumbnailIf( m_expanded ); - showHide(); + showHide(); + break; + + case R.id.view_loaded: + toggleSelected(); + break; + + case R.id.right_side: + if ( null != m_summary ) { + m_cb.itemClicked( GameListItem.this, m_summary ); + } + break; + default: + Assert.assertFalse(BuildConfig.DEBUG); + break; + } } private void findViews() @@ -191,12 +200,15 @@ public class GameListItem extends LinearLayout m_expandButton.setOnClickListener( this ); m_viewUnloaded = (TextView)findViewById( R.id.view_unloaded ); m_viewLoaded = findViewById( R.id.view_loaded ); + m_viewLoaded.setOnClickListener( this ); m_list = (LinearLayout)findViewById( R.id.player_list ); m_state = (TextView)findViewById( R.id.state ); m_modTime = (TextView)findViewById( R.id.modtime ); - m_marker = (ImageView)findViewById( R.id.msg_marker ); + m_gameTypeImage = (ImageView)findViewById( R.id.game_type_marker ); m_thumb = (ImageView)findViewById( R.id.thumbnail ); m_role = (TextView)findViewById( R.id.role ); + + findViewById( R.id.right_side ).setOnClickListener( this ); } private void setLoaded( boolean loaded ) @@ -316,19 +328,20 @@ public class GameListItem extends LinearLayout int iconID = summary.isMultiGame() ? R.drawable.multigame__gen : R.drawable.sologame__gen; - m_marker.setImageResource( iconID ); - m_marker.setOnClickListener( new View.OnClickListener() { - @Override - public void onClick( View view ) { - toggleSelected(); - } - } ); + m_gameTypeImage.setImageResource( iconID ); + + boolean hasChat = summary.isMultiGame(); + if ( hasChat ) { + int flags = DBUtils.getMsgFlags( m_context, m_rowid ); + hasChat = 0 != (flags & GameSummary.MSG_FLAGS_CHAT); + } + findViewById( R.id.has_chat_marker ) + .setVisibility( hasChat ? View.VISIBLE : View.GONE ); String roleSummary = summary.summarizeRole( m_context, m_rowid ); + m_role.setVisibility( null == roleSummary ? View.GONE : View.VISIBLE ); if ( null != roleSummary ) { m_role.setText( roleSummary ); - } else { - m_role.setVisibility( View.GONE ); } update( expanded, summary.lastMoveTime, haveATurn, @@ -420,6 +433,7 @@ public class GameListItem extends LinearLayout // } // GameListAdapter.ClickHandler interface + @Override public void longClicked() { toggleSelected(); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameUtils.java index dba4c57de..92c476792 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameUtils.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GameUtils.java @@ -1196,7 +1196,7 @@ public class GameUtils { for ( CommsConnType typ : conTypes ) { switch ( typ ) { case COMMS_CONN_RELAY: - tellRelayDied( context, summary, informNow ); + // see below break; case COMMS_CONN_BT: BTService.gameDied( context, addr.bt_btAddr, gameID ); @@ -1210,6 +1210,14 @@ public class GameUtils { } } } + + // comms doesn't have a relay address for us until the game's + // in play (all devices registered, at least.) To enable + // deleting on relay half-games that we created but nobody + // joined, special-case this one. + if ( summary.inRelayGame() ) { + tellRelayDied( context, summary, informNow ); + } gamePtr.release(); } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GamesListDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GamesListDelegate.java index e98aecd9f..41ffeeaea 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GamesListDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/GamesListDelegate.java @@ -564,6 +564,7 @@ public class GamesListDelegate extends ListDelegateBase private static final int[] DEBUG_ITEMS = { // R.id.games_menu_loaddb, R.id.games_menu_storedb, + R.id.games_menu_writegit, }; private static final int[] NOSEL_ITEMS = { R.id.games_menu_newgroup, @@ -754,9 +755,18 @@ public class GamesListDelegate extends ListDelegateBase lstnr = new OnClickListener() { public void onClick( DialogInterface dlg, int item ) { String name = namer.getName(); - DBUtils.addGroup( m_activity, name ); - mkListAdapter(); - showNewGroupIf(); + long hasName = DBUtils.getGroup( m_activity, name ); + if ( DBUtils.GROUPID_UNSPEC == hasName ) { + DBUtils.addGroup( m_activity, name ); + mkListAdapter(); + showNewGroupIf(); + } else { + String msg = LocUtils + .getString( m_activity, + R.string.duplicate_group_name_fmt, + name ); + makeOkOnlyBuilder( msg ).show(); + } } }; lstnr2 = new OnClickListener() { @@ -1059,8 +1069,6 @@ public class GamesListDelegate extends ListDelegateBase invalidateOptionsMenuIf(); setTitle(); } - - mkListAdapter(); } public void invalidateOptionsMenuIf() @@ -1132,6 +1140,9 @@ public class GamesListDelegate extends ListDelegateBase mkListAdapter(); setSelGame( rowid ); break; + case GAME_MOVED: + mkListAdapter(); + break; default: Assert.fail(); break; @@ -1539,10 +1550,10 @@ public class GamesListDelegate extends ListDelegateBase GameUtils.resendAllIf( m_activity, null, true, true ); break; case R.id.games_menu_newgame_solo: - handleNewGame( true ); + handleNewGameButton( true ); break; case R.id.games_menu_newgame_net: - handleNewGame( false ); + handleNewGameButton( false ); break; case R.id.games_menu_newgroup: @@ -1597,6 +1608,10 @@ public class GamesListDelegate extends ListDelegateBase Action.STORAGE_CONFIRMED, itemID ); break; + case R.id.games_menu_writegit: + Utils.gitInfoToClip( m_activity ); + break; + default: handled = handleSelGamesItem( itemID, selRowIDs ) || handleSelGroupsItem( itemID, getSelGroupIDs() ); diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/NetUtils.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/NetUtils.java index 62ff478da..78c43b68e 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/NetUtils.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/NetUtils.java @@ -184,7 +184,7 @@ public class NetUtils { short len = dis.readShort(); if ( len > 0 ) { byte[] packet = new byte[len]; - dis.read( packet ); + dis.readFully( packet ); msgs[ii][jj] = packet; } } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RefreshNamesTask.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RefreshNamesTask.java index f94f04725..9844be6d8 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RefreshNamesTask.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RefreshNamesTask.java @@ -94,7 +94,7 @@ public class RefreshNamesTask extends AsyncTask { // Can't figure out how to read a null-terminated string // from DataInputStream so parse it myself. byte[] bytes = new byte[len]; - dis.read( bytes ); + dis.readFully( bytes ); int index = -1; for ( int ii = 0; ii < nRooms; ++ii ) { diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayService.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayService.java index 740aa945d..89c24ebb4 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayService.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/RelayService.java @@ -736,7 +736,7 @@ public class RelayService extends XWService case XWPDEV_MSG: int token = dis.readInt(); byte[] msg = new byte[dis.available()]; - dis.read( msg ); + dis.readFully( msg ); postData( this, token, msg ); // game-related packets only count @@ -756,9 +756,8 @@ public class RelayService extends XWService resetBackoff = true; intent = getIntentTo( this, MsgCmds.GOT_INVITE ); int srcDevID = dis.readInt(); - short len = dis.readShort(); - byte[] nliData = new byte[len]; - dis.read( nliData ); + byte[] nliData = new byte[dis.readShort()]; + dis.readFully( nliData ); NetLaunchInfo nli = XwJNI.nliFromStream( nliData ); intent.putExtra( INVITE_FROM, srcDevID ); String asStr = nli.toString(); @@ -995,9 +994,8 @@ public class RelayService extends XWService private String getVLIString( DataInputStream dis ) throws java.io.IOException { - int len = vli2un( dis ); - byte[] tmp = new byte[len]; - dis.read( tmp ); + byte[] tmp = new byte[vli2un( dis )]; + dis.readFully( tmp ); String result = new String( tmp ); return result; } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/SMSService.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/SMSService.java index 38c1bef61..c5a226eec 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/SMSService.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/SMSService.java @@ -522,7 +522,7 @@ public class SMSService extends XWService { case DATA: int gameID = dis.readInt(); byte[] rest = new byte[dis.available()]; - dis.read( rest ); + dis.readFully( rest ); if ( feedMessage( gameID, rest, new CommsAddrRec( phone ) ) ) { SMSResendReceiver.resetTimer( this ); } @@ -618,7 +618,7 @@ public class SMSService extends XWService { } else { SMS_CMD cmd = SMS_CMD.values()[dis.readByte()]; byte[] rest = new byte[dis.available()]; - dis.read( rest ); + dis.readFully( rest ); receive( cmd, rest, senderPhone ); success = true; } diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/StudyListDelegate.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/StudyListDelegate.java index eed42cdee..db51df1f4 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/StudyListDelegate.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/StudyListDelegate.java @@ -50,6 +50,7 @@ public class StudyListDelegate extends ListDelegateBase implements OnItemSelectedListener, SelectableItem, View.OnLongClickListener, View.OnClickListener, DBUtils.StudyListListener { + private static final String TAG = StudyListDelegate.class.getSimpleName(); protected static final int NO_LANG = -1; @@ -220,7 +221,8 @@ public class StudyListDelegate extends ListDelegateBase showToast( msg ); break; default: - Assert.assertFalse( BuildConfig.DEBUG ); + Log.d( TAG, "not handling: %s", action ); + handled = false; break; } return handled; diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/Utils.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/Utils.java index e76107259..de49a2c2f 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/Utils.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/Utils.java @@ -32,7 +32,9 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.res.AssetManager; import android.content.res.Configuration; +import android.text.ClipboardManager; import android.database.Cursor; import android.media.Ringtone; @@ -55,9 +57,12 @@ import android.widget.Toast; import org.json.JSONException; import org.json.JSONObject; +import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; @@ -187,6 +192,33 @@ public class Utils { context.startActivity( Intent.createChooser( intent, chooserMsg ) ); } + static void gitInfoToClip( Context context ) + { + StringBuilder sb; + try { + InputStream is = context.getAssets().open( BuildConfig.BUILD_INFO_NAME, + AssetManager.ACCESS_BUFFER ); + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + sb = new StringBuilder(); + for ( ; ; ) { + String line = reader.readLine(); + if ( null == line ) { + break; + } + sb.append( line ).append( "\n" ); + } + reader.close(); + } catch ( Exception ex ) { + sb = null; + } + + if ( null != sb ) { + ClipboardManager clipboard = (ClipboardManager) + context.getSystemService(Context.CLIPBOARD_SERVICE); + clipboard.setText( sb.toString() ); + } + } + public static void postNotification( Context context, Intent intent, int titleID, int bodyID, int id ) { diff --git a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWApp.java b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWApp.java index f37658925..dbf740b99 100644 --- a/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWApp.java +++ b/xwords4/android/app/src/main/java/org/eehouse/android/xw4/XWApp.java @@ -36,7 +36,6 @@ public class XWApp extends Application { private static final String TAG = XWApp.class.getSimpleName(); public static final boolean BTSUPPORTED = true; - public static final boolean GCMSUPPORTED = true; public static final boolean ATTACH_SUPPORTED = false; public static final boolean LOG_LIFECYLE = false; public static final boolean DEBUG_EXP_TIMERS = false; @@ -53,6 +52,9 @@ public class XWApp extends Application { public static final int MAX_TRAY_TILES = 7; // comtypes.h public static final int SEL_COLOR = Color.argb( 0xFF, 0x09, 0x70, 0x93 ); + public static final int GREEN = 0xFF00AF00; + public static final int RED = 0xFFAF0000; + private static UUID s_UUID = null; private static Boolean s_onEmulator = null; private static Context s_context = null; diff --git a/xwords4/android/app/src/main/res/.gitignore b/xwords4/android/app/src/main/res/.gitignore index 1e3315a64..e19e5a0cb 100644 --- a/xwords4/android/app/src/main/res/.gitignore +++ b/xwords4/android/app/src/main/res/.gitignore @@ -1 +1,2 @@ values-??/strings.xml +**/*__gen.png diff --git a/xwords4/android/app/src/main/res/layout/chat.xml b/xwords4/android/app/src/main/res/layout/chat.xml index cdaa787cd..b0ac5d6eb 100644 --- a/xwords4/android/app/src/main/res/layout/chat.xml +++ b/xwords4/android/app/src/main/res/layout/chat.xml @@ -30,7 +30,6 @@ diff --git a/xwords4/android/app/src/main/res/layout/dict_browser.xml b/xwords4/android/app/src/main/res/layout/dict_browser.xml index 15ea2f71c..f83534566 100644 --- a/xwords4/android/app/src/main/res/layout/dict_browser.xml +++ b/xwords4/android/app/src/main/res/layout/dict_browser.xml @@ -26,7 +26,8 @@ - + + + + - @@ -66,7 +81,7 @@ android:layout_height="wrap_content" android:gravity="center" android:layout_weight="1" - android:singleLine="true" + android:maxLines="1" android:textAppearance="?android:attr/textAppearanceMedium" /> diff --git a/xwords4/android/app/src/main/res/layout/get_relay.xml b/xwords4/android/app/src/main/res/layout/get_relay.xml index 186f92600..6c37c233e 100644 --- a/xwords4/android/app/src/main/res/layout/get_relay.xml +++ b/xwords4/android/app/src/main/res/layout/get_relay.xml @@ -19,7 +19,8 @@ android:layout_marginLeft="30dip" android:layout_marginRight="30dip" android:autoText="false" - android:singleLine="true" + android:maxLines="1" + android:inputType="text" android:selectAllOnFocus="true" android:textAppearance="?android:attr/textAppearanceMedium" /> @@ -37,7 +38,8 @@ android:layout_marginLeft="30dip" android:layout_marginRight="30dip" android:autoText="false" - android:singleLine="true" + android:maxLines="1" + android:inputType="text" android:selectAllOnFocus="true" android:textAppearance="?android:attr/textAppearanceMedium" /> diff --git a/xwords4/android/app/src/main/res/layout/get_sms.xml b/xwords4/android/app/src/main/res/layout/get_sms.xml index 118fddcf4..e19a11073 100644 --- a/xwords4/android/app/src/main/res/layout/get_sms.xml +++ b/xwords4/android/app/src/main/res/layout/get_sms.xml @@ -19,7 +19,8 @@ android:layout_marginLeft="30dip" android:layout_marginRight="30dip" android:autoText="false" - android:singleLine="true" + android:maxLines="1" + android:inputType="text" android:selectAllOnFocus="true" android:textAppearance="?android:attr/textAppearanceMedium" /> @@ -37,7 +38,8 @@ android:layout_marginLeft="30dip" android:layout_marginRight="30dip" android:autoText="false" - android:singleLine="true" + android:maxLines="1" + android:inputType="text" android:selectAllOnFocus="true" android:textAppearance="?android:attr/textAppearanceMedium" /> diff --git a/xwords4/android/app/src/main/res/layout/list_item.xml b/xwords4/android/app/src/main/res/layout/list_item.xml index 5b8b1f555..4aa520d2b 100644 --- a/xwords4/android/app/src/main/res/layout/list_item.xml +++ b/xwords4/android/app/src/main/res/layout/list_item.xml @@ -31,7 +31,7 @@ android:layout_height="wrap_content" android:layout_weight="1" android:textAppearance="?android:attr/textAppearanceMedium" - android:singleLine="true" + android:maxLines="1" /> diff --git a/xwords4/android/app/src/main/res/layout/loc_list_item.xml b/xwords4/android/app/src/main/res/layout/loc_list_item.xml index e3d1d9f8b..48326a1a6 100644 --- a/xwords4/android/app/src/main/res/layout/loc_list_item.xml +++ b/xwords4/android/app/src/main/res/layout/loc_list_item.xml @@ -9,11 +9,11 @@ diff --git a/xwords4/android/app/src/main/res/layout/loc_main.xml b/xwords4/android/app/src/main/res/layout/loc_main.xml index 8fad9f96a..210f54c4b 100644 --- a/xwords4/android/app/src/main/res/layout/loc_main.xml +++ b/xwords4/android/app/src/main/res/layout/loc_main.xml @@ -37,7 +37,8 @@ diff --git a/xwords4/android/app/src/main/res/layout/msg_label_and_edit.xml b/xwords4/android/app/src/main/res/layout/msg_label_and_edit.xml index 1e4327dda..68c381039 100644 --- a/xwords4/android/app/src/main/res/layout/msg_label_and_edit.xml +++ b/xwords4/android/app/src/main/res/layout/msg_label_and_edit.xml @@ -18,8 +18,9 @@ android:layout_height="wrap_content" android:layout_width="fill_parent" android:scrollHorizontally="true" - android:autoText="false" - android:capitalize="none" + android:maxLines="1" + android:inputType="textCapWords" + android:maxLength="32" android:textAppearance="?android:attr/textAppearanceMedium" android:selectAllOnFocus="true" /> diff --git a/xwords4/android/app/src/main/res/layout/player_edit.xml b/xwords4/android/app/src/main/res/layout/player_edit.xml index cf5427b14..84679f3a8 100644 --- a/xwords4/android/app/src/main/res/layout/player_edit.xml +++ b/xwords4/android/app/src/main/res/layout/player_edit.xml @@ -51,11 +51,11 @@ android:layout_marginLeft="20dip" android:layout_marginRight="20dip" android:scrollHorizontally="true" - android:autoText="false" - android:capitalize="words" android:selectAllOnFocus="true" android:gravity="fill_horizontal" - android:singleLine="true" + android:maxLines="1" + android:maxLength="32" + android:inputType="textCapWords" android:textAppearance="?android:attr/textAppearanceMedium" /> @@ -101,11 +101,9 @@ android:layout_marginLeft="20dip" android:layout_marginRight="20dip" android:scrollHorizontally="true" - android:autoText="false" - android:capitalize="none" android:gravity="fill_horizontal" - android:password="true" - android:singleLine="true" + android:maxLines="1" + android:inputType="textPassword" android:textAppearance="?android:attr/textAppearanceMedium" /> diff --git a/xwords4/android/app/src/main/res/layout/player_list_elem.xml b/xwords4/android/app/src/main/res/layout/player_list_elem.xml index f8c865a1d..a2092b6d2 100644 --- a/xwords4/android/app/src/main/res/layout/player_list_elem.xml +++ b/xwords4/android/app/src/main/res/layout/player_list_elem.xml @@ -8,14 +8,14 @@ > diff --git a/xwords4/android/app/src/main/res/layout/rename_game.xml b/xwords4/android/app/src/main/res/layout/rename_game.xml index f6dca767b..fbeb59890 100644 --- a/xwords4/android/app/src/main/res/layout/rename_game.xml +++ b/xwords4/android/app/src/main/res/layout/rename_game.xml @@ -20,7 +20,8 @@ android:layout_marginLeft="30dip" android:layout_marginRight="30dip" android:autoText="false" - android:singleLine="true" + android:maxLines="1" + android:inputType="text" android:selectAllOnFocus="true" android:textAppearance="?android:attr/textAppearanceMedium" /> diff --git a/xwords4/android/app/src/main/res/menu/board_menu.xml b/xwords4/android/app/src/main/res/menu/board_menu.xml index 35e3997ef..f49b85f19 100644 --- a/xwords4/android/app/src/main/res/menu/board_menu.xml +++ b/xwords4/android/app/src/main/res/menu/board_menu.xml @@ -57,7 +57,7 @@ - diff --git a/xwords4/android/app/src/main/res/menu/games_list_menu.xml b/xwords4/android/app/src/main/res/menu/games_list_menu.xml index fb964160a..078a860ad 100644 --- a/xwords4/android/app/src/main/res/menu/games_list_menu.xml +++ b/xwords4/android/app/src/main/res/menu/games_list_menu.xml @@ -120,5 +120,8 @@ + diff --git a/xwords4/android/app/src/main/res/values-v11/themes.xml b/xwords4/android/app/src/main/res/values-v11/themes.xml new file mode 100644 index 000000000..0d55c6559 --- /dev/null +++ b/xwords4/android/app/src/main/res/values-v11/themes.xml @@ -0,0 +1,4 @@ + + +