mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-08 05:24:39 +01:00
Merge remote-tracking branch 'origin/android_translate' into android_translate
This commit is contained in:
commit
11368df086
20 changed files with 237 additions and 306 deletions
2
xwords4/android/.gitignore
vendored
2
xwords4/android/.gitignore
vendored
|
@ -3,3 +3,5 @@
|
|||
local.properties
|
||||
.idea
|
||||
app/src/main/assets/build-info.txt
|
||||
obj-*
|
||||
libs-*
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
def INITIAL_CLIENT_VERS = 8
|
||||
def VERSION_CODE_BASE = 119
|
||||
def VERSION_NAME = '4.4.123'
|
||||
def VERSION_CODE_BASE = 121
|
||||
def VERSION_NAME = '4.4.125'
|
||||
def FABRIC_API_KEY = System.getenv("FABRIC_API_KEY")
|
||||
|
||||
boolean forFDroid = hasProperty('forFDroid')
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
<!-- BE SURE TO MODIFY project.properties AND the variable TARGET in
|
||||
../scripts/setup_local_props.sh if targetSdkVersion changes!!!
|
||||
-->
|
||||
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="23" />
|
||||
|
||||
<supports-screens android:resizeable="true"
|
||||
android:smallScreens="true"
|
||||
android:normalScreens="true"
|
||||
|
@ -48,6 +46,7 @@
|
|||
<application android:icon="@drawable/icon48x48"
|
||||
android:label="@string/app_name"
|
||||
android:name=".XWApp"
|
||||
android:theme="@style/AppTheme"
|
||||
>
|
||||
|
||||
<activity android:name="MainActivity"
|
||||
|
@ -84,9 +83,6 @@
|
|||
<activity android:name="RelayInviteActivity"
|
||||
android:label="@string/relay_invite_title"
|
||||
/>
|
||||
<activity android:name="WiDirInviteActivity"
|
||||
android:label="@string/p2p_invite_title"
|
||||
/>
|
||||
|
||||
<activity android:name="GameConfigActivity"
|
||||
android:screenOrientation="sensor"
|
||||
|
|
|
@ -13,9 +13,10 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h2>CrossWords 4.4.123 release</h2>
|
||||
<h2>CrossWords 4.4.125 release</h2>
|
||||
|
||||
<p>This is a quick bug-fix release.</p>
|
||||
<p>This release fixes a problem inviting to new networked games, and
|
||||
with title bars on some Samsung devices.</p>
|
||||
|
||||
<div id="survey">
|
||||
<p>Please <a href="https://www.surveymonkey.com/s/GX3XLHR">take
|
||||
|
@ -25,8 +26,10 @@
|
|||
|
||||
<h3>New with this release</h3>
|
||||
<ul>
|
||||
<li>Fix crash when invitation requires a wordlist you don't have</li>
|
||||
<li>Include latest Portuguese translations</li>
|
||||
<li>Fix delays bringing up the Invite dialog for new games</li>
|
||||
<li>Explicitly specify application "theme" to fix a Samsung
|
||||
"upgrade" turning the titlebar white and so making menu
|
||||
icons disappear</li>
|
||||
</ul>
|
||||
|
||||
<p>(The full changelog
|
||||
|
|
|
@ -126,6 +126,7 @@ public class BoardDelegate extends DelegateBase
|
|||
private boolean m_overNotShown;
|
||||
private boolean m_dropOnDismiss;
|
||||
private DBAlert m_inviteAlert;
|
||||
private boolean m_haveStartedShowing;
|
||||
|
||||
public class TimerRunnable implements Runnable {
|
||||
private int m_why;
|
||||
|
@ -2225,6 +2226,7 @@ public class BoardDelegate extends DelegateBase
|
|||
// Assert.assertFalse( BuildConfig.DEBUG );
|
||||
}
|
||||
m_inviteAlert = null;
|
||||
m_haveStartedShowing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2304,9 +2306,14 @@ public class BoardDelegate extends DelegateBase
|
|||
showDialogFragment( dlgID, dlgTitle, txt );
|
||||
}
|
||||
|
||||
// This is failing sometimes, and so the null == m_inviteAlert test means
|
||||
// we never post it. BUT on a lot of devices without the test we wind up
|
||||
// trying over and over to put the thing up.
|
||||
private void showInviteAlertIf()
|
||||
{
|
||||
if ( /* null == m_inviteAlert && */m_mySIS.nMissing > 0 && !isFinishing() ) {
|
||||
DbgUtils.assertOnUIThread();
|
||||
if ( ! m_haveStartedShowing && null == m_inviteAlert
|
||||
&& m_mySIS.nMissing > 0 && !isFinishing() ) {
|
||||
InviteAlertState ias = new InviteAlertState();
|
||||
ias.summary = m_summary;
|
||||
ias.gi = m_gi;
|
||||
|
@ -2315,6 +2322,7 @@ public class BoardDelegate extends DelegateBase
|
|||
ias.rowid = m_rowid;
|
||||
ias.nMissing = m_mySIS.nMissing;
|
||||
showDialogFragment( DlgID.DLG_INVITE, ias );
|
||||
m_haveStartedShowing = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -84,14 +84,24 @@ public class ConnStatusHandler {
|
|||
|
||||
public String newerStr( Context context )
|
||||
{
|
||||
s_time.set( successNewer? lastSuccess : lastFailure );
|
||||
return format( context, s_time );
|
||||
String result = null;
|
||||
long time = successNewer? lastSuccess : lastFailure;
|
||||
if ( time > 0 ) {
|
||||
s_time.set( time );
|
||||
result = format( context, s_time );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String olderStr( Context context )
|
||||
{
|
||||
s_time.set( successNewer? lastFailure : lastSuccess );
|
||||
return format( context, s_time );
|
||||
String result = null;
|
||||
long time = successNewer? lastFailure : lastSuccess;
|
||||
if ( time > 0 ) {
|
||||
s_time.set( time );
|
||||
result = format( context, s_time );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void update( boolean success )
|
||||
|
@ -175,13 +185,20 @@ public class ConnStatusHandler {
|
|||
String did = addDebugInfo( context, typ );
|
||||
sb.append( String.format( "\n\n*** %s %s***\n",
|
||||
typ.longName( context ), did ) );
|
||||
|
||||
// For sends we list failures too.
|
||||
SuccessRecord record = recordFor( typ, false );
|
||||
tmp = LocUtils.getString( context, record.successNewer?
|
||||
R.string.connstat_succ :
|
||||
R.string.connstat_unsucc );
|
||||
sb.append( LocUtils
|
||||
.getString( context, R.string.connstat_lastsend_fmt,
|
||||
tmp, record.newerStr( context ) ) );
|
||||
|
||||
String timeStr = record.newerStr( context );
|
||||
if ( null != timeStr ) {
|
||||
sb.append( LocUtils
|
||||
.getString( context, R.string.connstat_lastsend_fmt,
|
||||
tmp, timeStr ) )
|
||||
.append( "\n" );
|
||||
}
|
||||
|
||||
int fmtId = 0;
|
||||
if ( record.successNewer ) {
|
||||
|
@ -193,11 +210,12 @@ public class ConnStatusHandler {
|
|||
fmtId = R.string.connstat_lastother_unsucc_fmt;
|
||||
}
|
||||
}
|
||||
if ( 0 != fmtId ) {
|
||||
sb.append( LocUtils.getString( context, fmtId,
|
||||
record.olderStr( context )));
|
||||
timeStr = record.olderStr( context );
|
||||
if ( 0 != fmtId && null != timeStr ) {
|
||||
sb.append( LocUtils.getString( context, fmtId, timeStr ))
|
||||
.append( "\n" );
|
||||
}
|
||||
sb.append( "\n\n" );
|
||||
sb.append( "\n" );
|
||||
|
||||
record = recordFor( typ, true );
|
||||
if ( record.haveSuccess() ) {
|
||||
|
|
|
@ -290,7 +290,7 @@ public class DelegateBase implements DlgClickNotify,
|
|||
if ( main.inDPMode() ) {
|
||||
if ( !m_finishCalled ) {
|
||||
m_finishCalled = true;
|
||||
main.finishFragment();
|
||||
main.finishFragment( (XWFragment)m_delegator );
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ import android.os.Bundle;
|
|||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eehouse.android.xw4.DBUtils.SentInvitesInfo;
|
||||
|
@ -126,13 +128,29 @@ public class DlgDelegate {
|
|||
SET_GOT_LANGDICT,
|
||||
}
|
||||
|
||||
public static class ActionPair {
|
||||
public static class ActionPair implements Serializable {
|
||||
public ActionPair( Action act, int str ) {
|
||||
buttonStr = str; action = act;
|
||||
}
|
||||
public int buttonStr;
|
||||
public Action action;
|
||||
public Object[] params; // null for now
|
||||
|
||||
@Override
|
||||
public boolean equals( Object obj )
|
||||
{
|
||||
boolean result;
|
||||
if ( BuildConfig.DEBUG ) {
|
||||
result = null != obj && obj instanceof ActionPair;
|
||||
if ( result ) {
|
||||
ActionPair other = (ActionPair)obj;
|
||||
result = buttonStr == other.buttonStr
|
||||
&& action == other.action;
|
||||
}
|
||||
} else {
|
||||
result = super.equals( obj );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class DlgDelegateBuilder {
|
||||
|
|
|
@ -164,6 +164,7 @@ public class DlgState implements Parcelable {
|
|||
out.writeInt( m_titleId );
|
||||
out.writeString( m_msg );
|
||||
out.writeSerializable( m_params );
|
||||
out.writeSerializable( m_pair );
|
||||
}
|
||||
|
||||
private void testCanParcelize()
|
||||
|
@ -197,6 +198,7 @@ public class DlgState implements Parcelable {
|
|||
int titleId = in.readInt();
|
||||
String msg = in.readString();
|
||||
Object[] params = (Object[])in.readSerializable();
|
||||
ActionPair pair = (ActionPair)in.readSerializable();
|
||||
DlgState state = new DlgState(id)
|
||||
.setMsg( msg )
|
||||
.setPosButton( posButton )
|
||||
|
@ -206,6 +208,7 @@ public class DlgState implements Parcelable {
|
|||
.setOnNA( onNA )
|
||||
.setTitle(titleId)
|
||||
.setParams(params)
|
||||
.setActionPair(pair)
|
||||
;
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -24,19 +24,20 @@ import android.app.Activity;
|
|||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemLongClickListener;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
|
@ -1926,8 +1927,19 @@ public class GamesListDelegate extends ListDelegateBase
|
|||
{
|
||||
m_mySIS.nextIsSolo = solo;
|
||||
|
||||
int count = m_adapter.getCount();
|
||||
boolean skipOffer = 6 > count || XWPrefs.getHideNewgameButtons( m_activity );
|
||||
boolean skipOffer = XWPrefs.getHideNewgameButtons( m_activity );
|
||||
if ( ! skipOffer ) {
|
||||
// If the API's availble, offer to hide buttons as soon as there
|
||||
// are enough games that the list is scrollable. Otherwise fall
|
||||
// back to there being at least four games.
|
||||
if ( Build.VERSION.SDK_INT >= 19 ) {
|
||||
ListView list = getListView();
|
||||
skipOffer = !list.canScrollList( 1 ) && !list.canScrollList( -1 );
|
||||
} else {
|
||||
skipOffer = 4 > m_adapter.getCount();
|
||||
}
|
||||
}
|
||||
|
||||
if ( skipOffer ) {
|
||||
handleNewGame( solo );
|
||||
} else {
|
||||
|
|
|
@ -298,11 +298,12 @@ public class MainActivity extends XWActivity
|
|||
resultCode, data );
|
||||
}
|
||||
|
||||
protected void finishFragment()
|
||||
protected void finishFragment( XWFragment fragment )
|
||||
{
|
||||
// Assert.assertTrue( fragment instanceof XWFragment );
|
||||
// Log.d( TAG, "finishFragment()" );
|
||||
getSupportFragmentManager().popBackStack/*Immediate*/();
|
||||
int ID = fragment.getCommitID();
|
||||
getSupportFragmentManager()
|
||||
.popBackStack( ID, FragmentManager.POP_BACK_STACK_INCLUSIVE );
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -453,14 +454,14 @@ public class MainActivity extends XWActivity
|
|||
return frag;
|
||||
}
|
||||
|
||||
private void addFragmentImpl( Fragment fragment, Bundle bundle,
|
||||
private void addFragmentImpl( XWFragment fragment, Bundle bundle,
|
||||
String parentName )
|
||||
{
|
||||
fragment.setArguments( bundle );
|
||||
addFragmentImpl( fragment, parentName );
|
||||
}
|
||||
|
||||
private void addFragmentImpl( final Fragment fragment,
|
||||
private void addFragmentImpl( final XWFragment fragment,
|
||||
final String parentName )
|
||||
{
|
||||
if ( m_safeToCommit ) {
|
||||
|
@ -497,7 +498,7 @@ public class MainActivity extends XWActivity
|
|||
}
|
||||
}
|
||||
|
||||
private void safeAddFragment( Fragment fragment, String parentName )
|
||||
private void safeAddFragment( XWFragment fragment, String parentName )
|
||||
{
|
||||
Assert.assertTrue( m_safeToCommit );
|
||||
String newName = fragment.getClass().getSimpleName();
|
||||
|
@ -505,10 +506,11 @@ public class MainActivity extends XWActivity
|
|||
|
||||
popUnneeded( fm, newName, parentName );
|
||||
|
||||
fm.beginTransaction()
|
||||
int ID = fm.beginTransaction()
|
||||
.add( R.id.main_container, fragment, newName )
|
||||
.addToBackStack( newName )
|
||||
.commit();
|
||||
fragment.setCommitID( ID );
|
||||
// Don't do this. It causes an exception if e.g. from fragment.start()
|
||||
// I wind up launching another fragment and calling into this code
|
||||
// again. If I need executePendingTransactions() I'm doing something
|
||||
|
|
|
@ -75,6 +75,7 @@ public class RelayInviteDelegate extends InviteDelegate {
|
|||
// private RelayDevsAdapter m_adapter;
|
||||
private boolean m_immobileConfirmed;
|
||||
private Activity m_activity;
|
||||
private String m_devIDStr;
|
||||
|
||||
public static void launchForResult( Activity activity, int nMissing,
|
||||
RequestCode requestCode )
|
||||
|
@ -101,6 +102,8 @@ public class RelayInviteDelegate extends InviteDelegate {
|
|||
super.init( msg, R.string.empty_relay_inviter );
|
||||
addButtonBar( R.layout.relay_buttons, BUTTONIDS );
|
||||
|
||||
m_devIDStr = String.format( "%d", DevID.getRelayDevIDInt(m_activity) );
|
||||
|
||||
// getBundledData( savedInstanceState );
|
||||
|
||||
// m_addButton = (ImageButton)findViewById( R.id.manual_add_button );
|
||||
|
@ -437,6 +440,21 @@ public class RelayInviteDelegate extends InviteDelegate {
|
|||
// }
|
||||
// } // addPhoneNumbers
|
||||
|
||||
private void addSelf()
|
||||
{
|
||||
boolean hasSelf = false;
|
||||
for ( DevIDRec rec : m_devIDRecs ) {
|
||||
if ( rec.m_devID.equals( m_devIDStr ) ) {
|
||||
hasSelf = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !hasSelf ) {
|
||||
DevIDRec rec = new DevIDRec( "me", m_devIDStr );
|
||||
m_devIDRecs.add( rec );
|
||||
}
|
||||
}
|
||||
|
||||
private void rebuildList( boolean checkIfAll )
|
||||
{
|
||||
Collections.sort( m_devIDRecs, new Comparator<DevIDRec>() {
|
||||
|
@ -444,15 +462,9 @@ public class RelayInviteDelegate extends InviteDelegate {
|
|||
return rec1.m_opponent.compareTo(rec2.m_opponent);
|
||||
}
|
||||
});
|
||||
|
||||
addSelf();
|
||||
updateListAdapter( m_devIDRecs.toArray( new DevIDRec[m_devIDRecs.size()] ) );
|
||||
// m_adapter = new RelayDevsAdapter();
|
||||
// setListAdapter( m_adapter );
|
||||
// if ( checkIfAll && m_devIDRecs.size() <= m_nMissing ) {
|
||||
// Iterator<DevIDRec> iter = m_devIDRecs.iterator();
|
||||
// while ( iter.hasNext() ) {
|
||||
// iter.next().m_isChecked = true;
|
||||
// }
|
||||
// }
|
||||
tryEnable();
|
||||
}
|
||||
|
||||
|
|
|
@ -177,7 +177,7 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
|
|||
params.put( k_STRINGSHASH, BuildConfig.STRINGS_HASH );
|
||||
params.put( k_NAME, packageName );
|
||||
params.put( k_AVERS, versionCode );
|
||||
Log.d( TAG, "current update: %s", params.toString() );
|
||||
// Log.d( TAG, "current update: %s", params.toString() );
|
||||
new UpdateQueryTask( context, params, fromUI, pm,
|
||||
packageName, dals ).execute();
|
||||
} catch ( org.json.JSONException jse ) {
|
||||
|
@ -278,6 +278,7 @@ public class UpdateCheckReceiver extends BroadcastReceiver {
|
|||
{
|
||||
boolean gotOne = false;
|
||||
try {
|
||||
// Log.d( TAG, "makeNotificationsIf(response=%s)", jstr );
|
||||
JSONObject jobj = new JSONObject( jstr );
|
||||
if ( null != jobj ) {
|
||||
|
||||
|
|
|
@ -511,8 +511,7 @@ public class Utils {
|
|||
new ObjectInputStream( new ByteArrayInputStream(bytes) );
|
||||
result = ois.readObject();
|
||||
} catch ( Exception ex ) {
|
||||
Log.ex( TAG, ex );
|
||||
Assert.assertFalse( BuildConfig.DEBUG );
|
||||
Log.d( TAG, ex.getMessage() );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -41,10 +41,12 @@ import junit.framework.Assert;
|
|||
abstract class XWFragment extends Fragment implements Delegator {
|
||||
private static final String TAG = XWFragment.class.getSimpleName();
|
||||
private static final String PARENT_NAME = "PARENT_NAME";
|
||||
private static final String COMMIT_ID = "COMMIT_ID";
|
||||
|
||||
private DelegateBase m_dlgt;
|
||||
private String m_parentName;
|
||||
private boolean m_hasOptionsMenu = false;
|
||||
private int m_commitID;
|
||||
|
||||
private static Set<XWFragment> sActiveFrags = new HashSet<XWFragment>();
|
||||
public static XWFragment findOwnsView( View view )
|
||||
|
@ -75,6 +77,9 @@ abstract class XWFragment extends Fragment implements Delegator {
|
|||
return m_parentName;
|
||||
}
|
||||
|
||||
public void setCommitID( int id ) { m_commitID = id; }
|
||||
public int getCommitID() { return m_commitID; }
|
||||
|
||||
protected void onCreate( DelegateBase dlgt, Bundle sis, boolean hasOptionsMenu )
|
||||
{
|
||||
m_hasOptionsMenu = hasOptionsMenu;
|
||||
|
@ -87,6 +92,7 @@ abstract class XWFragment extends Fragment implements Delegator {
|
|||
Log.d( TAG, "%s.onSaveInstanceState() called", getClass().getSimpleName() );
|
||||
Assert.assertNotNull( m_parentName );
|
||||
outState.putString( PARENT_NAME, m_parentName );
|
||||
outState.putInt( COMMIT_ID, m_commitID );
|
||||
m_dlgt.onSaveInstanceState( outState );
|
||||
super.onSaveInstanceState( outState );
|
||||
}
|
||||
|
@ -98,6 +104,7 @@ abstract class XWFragment extends Fragment implements Delegator {
|
|||
if ( null != sis ) {
|
||||
m_parentName = sis.getString( PARENT_NAME );
|
||||
Assert.assertNotNull( m_parentName );
|
||||
m_commitID = sis.getInt( COMMIT_ID );
|
||||
}
|
||||
Assert.assertNull( m_dlgt );
|
||||
m_dlgt = dlgt;
|
||||
|
|
|
@ -749,10 +749,11 @@ public class JNIThread extends Thread {
|
|||
|
||||
public void handle( JNICmd cmd, Object... args )
|
||||
{
|
||||
m_queue.add( new QueueElem( cmd, true, args ) );
|
||||
if ( m_stopped && ! JNICmd.CMD_NONE.equals(cmd) ) {
|
||||
Log.w( TAG, "adding %s to stopped thread!!!", cmd.toString() );
|
||||
Log.w( TAG, "NOT adding %s to stopped thread!!!", cmd.toString() );
|
||||
DbgUtils.printStack( TAG );
|
||||
} else {
|
||||
m_queue.add( new QueueElem( cmd, true, args ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<style name="AppTheme" parent="android:Theme.Material"/>
|
||||
|
||||
<style name="config_separator">
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:layout_width">fill_parent</item>
|
||||
|
|
|
@ -1,248 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!-- Declare the contents of this Android application. The namespace
|
||||
attribute brings in the Android platform namespace, and the package
|
||||
supplies a unique name for the application. When writing your
|
||||
own application, the package name must be changed from "com.example.*"
|
||||
to come from a domain that you own or have control over. -->
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.eehouse.android.xw4"
|
||||
>
|
||||
|
||||
<!-- BE SURE TO MODIFY project.properties AND the variable TARGET in
|
||||
../scripts/setup_local_props.sh if targetSdkVersion changes!!!
|
||||
-->
|
||||
<supports-screens android:resizeable="true"
|
||||
android:smallScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:largeScreens="true"
|
||||
android:xlargeScreens="true"
|
||||
/>
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="android.permission.VIBRATE" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_SMS" />
|
||||
<uses-permission android:name="android.permission.SEND_SMS" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.READ_CONTACTS" />
|
||||
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
|
||||
|
||||
<!-- Added for wifi-direct; don't ship until move to 23!!! -->
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||
|
||||
<uses-feature android:name="android.hardware.telephony"
|
||||
android:required = "false"
|
||||
/>
|
||||
<uses-feature android:name="android.hardware.nfc" android:required="false" />
|
||||
|
||||
<!-- GCM stuff -->
|
||||
<permission android:name="${APP_ID}.permission.C2D_MESSAGE"
|
||||
android:protectionLevel="signature" />
|
||||
<uses-permission android:name="${APP_ID}.permission.C2D_MESSAGE" />
|
||||
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
|
||||
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
|
||||
<!-- for crittercism -->
|
||||
<uses-permission android:name="android.permission.GET_TASKS"/>
|
||||
|
||||
<application android:icon="@drawable/icon48x48"
|
||||
android:label="@string/app_name"
|
||||
android:name=".XWApp"
|
||||
android:theme="@style/AppTheme"
|
||||
>
|
||||
|
||||
<activity android:name="MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="standard"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:mimeType="@string/xwords_nfc_mime" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- NOT in the non-d version -->
|
||||
<meta-data android:name="io.fabric.ApiKey" android:value="${FABRIC_API_KEY}" />
|
||||
|
||||
<activity android:name="DictsActivity"
|
||||
android:label="@string/title_dicts_list"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
|
||||
<activity android:name="BTInviteActivity"
|
||||
android:label="@string/bt_invite_title"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
<activity android:name="SMSInviteActivity"
|
||||
android:label="@string/sms_invite_title"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:screenOrientation="sensor"
|
||||
/>
|
||||
<activity android:name="RelayInviteActivity"
|
||||
android:label="@string/relay_invite_title"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
<activity android:name="WiDirInviteActivity"
|
||||
android:label="@string/p2p_invite_title"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
|
||||
<activity android:name="GameConfigActivity"
|
||||
android:screenOrientation="sensor"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:windowSoftInputMode="stateAlwaysHidden"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.EDIT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="PrefsActivity"
|
||||
android:label="@string/title_prefs"
|
||||
android:screenOrientation="sensor"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
|
||||
<activity android:name="BoardActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
android:windowSoftInputMode="stateAlwaysHidden|adjustPan"
|
||||
/>
|
||||
|
||||
<activity android:name="StudyListActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
|
||||
<receiver android:name="OnBootReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver android:name="RelayReceiver"/>
|
||||
<receiver android:name="NagTurnReceiver"/>
|
||||
|
||||
<receiver android:name="UpdateCheckReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<activity android:name="DispatchNotify">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="newxwgame"/>
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="http"
|
||||
android:host="@string/invite_host"
|
||||
android:pathPrefix="@string/invite_prefix"
|
||||
/>
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:mimeType="@string/invite_mime" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- downloading dicts -->
|
||||
<activity android:name=".DwnldActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.Dialog"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW"></action>
|
||||
<category android:name="android.intent.category.DEFAULT"></category>
|
||||
<category android:name="android.intent.category.BROWSABLE"></category>
|
||||
<data android:scheme="file" android:host="*"
|
||||
android:pathPattern=".*\\.xwd" />
|
||||
<data android:scheme="http"
|
||||
android:mimeType="application/x-xwordsdict"
|
||||
android:host="*"
|
||||
android:pathPattern=".*\\.xwd" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity android:name="DictBrowseActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
<activity android:name="ChatActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
<activity android:name=".loc.LocActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
<activity android:name=".loc.LocItemEditActivity"
|
||||
android:configChanges="keyboardHidden|orientation|screenSize"
|
||||
/>
|
||||
|
||||
<service android:name="RelayService"/>
|
||||
<service android:name="BTService"/>
|
||||
<service android:name="WiDirService"/>
|
||||
<service android:name="SMSService"/>
|
||||
|
||||
<receiver android:name=".MountEventReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MEDIA_MOUNTED" />
|
||||
<data android:scheme="file" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MEDIA_EJECT" />
|
||||
<data android:scheme="file" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="BTReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.bluetooth.device.action.ACL_CONNECTED" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="SMSReceiver" >
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.DATA_SMS_RECEIVED" />
|
||||
<data android:scheme="sms" />
|
||||
<data android:port="@string/nbs_port" />
|
||||
<data android:host="*" />
|
||||
</intent-filter>
|
||||
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="com.google.android.gcm.GCMBroadcastReceiver"
|
||||
android:permission="com.google.android.c2dm.permission.SEND" >
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
||||
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
|
||||
<category android:name="${APP_ID}" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<service android:name=".GCMIntentService" />
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#!/usr/bin/python
|
||||
# Script meant to be installed on eehouse.org.
|
||||
|
||||
import logging, shelve, hashlib, sys, json, subprocess, glob, os, struct, random, string, psycopg2
|
||||
import logging, shelve, hashlib, sys, re, json, subprocess, glob, os
|
||||
import struct, random, string, psycopg2, zipfile
|
||||
import mk_for_download, mygit
|
||||
import xwconfig
|
||||
|
||||
|
@ -54,6 +55,10 @@ k_LANGSVERS = 'lvers'
|
|||
# Version for those sticking with RELEASES
|
||||
k_REL_REV = 'android_beta_98'
|
||||
|
||||
# newer build-info.txt file contain lines like this:
|
||||
# git: android_beta_123
|
||||
pat_git_tag = re.compile( 'git: (\S*)', re.DOTALL | re.MULTILINE )
|
||||
|
||||
# Version for those getting intermediate builds
|
||||
|
||||
k_suffix = '.xwd'
|
||||
|
@ -164,20 +169,59 @@ def getDictSums():
|
|||
openShelf()
|
||||
return s_shelf[k_SUMS]
|
||||
|
||||
def getOrderedApks( path, debug ):
|
||||
# logging.debug( "getOrderedApks(" + path + ")" )
|
||||
apks = []
|
||||
def getGitRevFor(file, repo):
|
||||
result = None
|
||||
zip = zipfile.ZipFile(file);
|
||||
|
||||
pattern = path
|
||||
if debug: pattern += "/XWords4-debug-android_*.apk"
|
||||
else: pattern += "/XWords4-release_*android_beta_*.apk"
|
||||
try:
|
||||
result = zip.read('assets/gitvers.txt').split("\n")[0]
|
||||
except KeyError, err:
|
||||
result = None
|
||||
|
||||
if not result:
|
||||
try:
|
||||
data = zip.read('assets/build-info.txt')
|
||||
match = pat_git_tag.match(data)
|
||||
if match:
|
||||
tag = match.group(1)
|
||||
if not 'dirty' in tag:
|
||||
result = repo.tagToRev(tag)
|
||||
except KeyError, err:
|
||||
None
|
||||
|
||||
# print "getGitRevFor(", file, "->", result
|
||||
return result
|
||||
|
||||
|
||||
pat_badge_info = re.compile("package: name='([^']*)' versionCode='([^']*)' versionName='([^']*)'", re.DOTALL )
|
||||
|
||||
def getAAPTInfo(file):
|
||||
result = None
|
||||
test = subprocess.Popen(["aapt", "dump", "badging", file], shell = False, stdout = subprocess.PIPE)
|
||||
for line in test.communicate():
|
||||
if line:
|
||||
match = pat_badge_info.match(line)
|
||||
if match:
|
||||
result = { 'appID' : match.group(1),
|
||||
'versionCode' : int(match.group(2)),
|
||||
'versionName' : match.group(3),
|
||||
}
|
||||
break
|
||||
return result
|
||||
|
||||
def getOrderedApks( path, appID, debug ):
|
||||
apkToCode = {}
|
||||
apkToMtime = {}
|
||||
if debug: pattern = path + "/*debug*.apk"
|
||||
else: pattern = path + "/*release*.apk"
|
||||
files = ((os.stat(apk).st_mtime, apk) for apk in glob.glob(pattern))
|
||||
for mtime, file in sorted(files, reverse=True):
|
||||
# logging.debug( file + ": " + str(mtime) )
|
||||
apks.append( file )
|
||||
|
||||
return apks
|
||||
info = getAAPTInfo(file)
|
||||
if info['appID'] == appID:
|
||||
apkToCode[file] = info['versionCode']
|
||||
apkToMtime[file] = mtime
|
||||
result = sorted(apkToCode.keys(), reverse=True, key=lambda file: (apkToCode[file], apkToMtime[file]))
|
||||
return result
|
||||
|
||||
def getVariantDir( name ):
|
||||
result = ''
|
||||
|
@ -236,7 +280,7 @@ def getApp( params, name ):
|
|||
# If we're a dev device, always push the latest
|
||||
if k_DEBUG in params and params[k_DEBUG]:
|
||||
dir = k_filebase + k_apkDir + variantDir
|
||||
apks = getOrderedApks( dir, True )
|
||||
apks = getOrderedApks( dir, name, True )
|
||||
if 0 < len(apks):
|
||||
apk = apks[0]
|
||||
curApk = params[k_GVERS] + '.apk'
|
||||
|
@ -247,7 +291,7 @@ def getApp( params, name ):
|
|||
logging.debug("url: " + url)
|
||||
result = {k_URL: url}
|
||||
elif k_DEVOK in params and params[k_DEVOK]:
|
||||
apks = getOrderedApks( k_filebase + k_apkDir, False )
|
||||
apks = getOrderedApks( k_filebase + k_apkDir, name, False )
|
||||
if 0 < len(apks):
|
||||
apk = apks[0]
|
||||
# Does path NOT contain name of installed file
|
||||
|
@ -259,19 +303,15 @@ def getApp( params, name ):
|
|||
result = {k_URL: url}
|
||||
logging.debug( result )
|
||||
|
||||
elif k_AVERS in params and k_GVERS in params:
|
||||
avers = params[k_AVERS]
|
||||
elif k_GVERS in params:
|
||||
gvers = params[k_GVERS]
|
||||
if k_INSTALLER in params: installer = params[k_INSTALLER]
|
||||
else: installer = ''
|
||||
|
||||
logging.debug( "name: %s; avers: %s; installer: %s; gvers: %s"
|
||||
% (name, avers, installer, gvers) )
|
||||
logging.debug( "name: %s; installer: %s; gvers: %s"
|
||||
% (name, installer, gvers) )
|
||||
if name in k_versions:
|
||||
versForName = k_versions[name]
|
||||
if versForName[k_AVERS] > int(avers):
|
||||
result = {k_URL: k_urlbase + '/' + versForName[k_URL]}
|
||||
elif k_GVERS in versForName and not gvers == versForName[k_GVERS]:
|
||||
if k_GVERS in versForName and not gvers == versForName[k_GVERS]:
|
||||
result = {k_URL: k_urlbase + '/' + versForName[k_URL]}
|
||||
else:
|
||||
logging.debug(name + " is up-to-date")
|
||||
|
@ -521,23 +561,25 @@ def clearShelf():
|
|||
for key in shelf: del shelf[key]
|
||||
shelf.close()
|
||||
|
||||
def usage():
|
||||
def usage(msg=None):
|
||||
if msg: print "ERROR:", msg
|
||||
print "usage:", sys.argv[0], '--get-sums [lang/dict]*'
|
||||
print ' | --test-get-app app <org.eehouse.app.name> avers gvers'
|
||||
print ' | --test-get-dicts name lang curSum'
|
||||
print ' | --list-apks [path/to/apks]'
|
||||
print ' | --list-apks [--path <path/to/apks>] [--debug] --appID org.something'
|
||||
print ' | --list-dicts'
|
||||
print ' | --opponent-ids-for'
|
||||
print ' | --clear-shelf'
|
||||
sys.exit(-1)
|
||||
|
||||
def main():
|
||||
if 1 >= len(sys.argv): usage();
|
||||
argc = len(sys.argv)
|
||||
if 1 >= argc: usage();
|
||||
arg = sys.argv[1]
|
||||
if arg == '--clear-shelf':
|
||||
clearShelf()
|
||||
elif arg == '--list-dicts':
|
||||
if 2 < len(sys.argv): lc = sys.argv[2]
|
||||
if 2 < argc: lc = sys.argv[2]
|
||||
else: lc = None
|
||||
dictsJson = listDicts( lc )
|
||||
print json.dumps( dictsJson )
|
||||
|
@ -548,14 +590,13 @@ def main():
|
|||
s_shelf[k_SUMS] = dictSums
|
||||
closeShelf()
|
||||
elif arg == '--test-get-app':
|
||||
if not 5 == len(sys.argv): usage()
|
||||
if not 4 == argc: usage()
|
||||
params = { k_NAME: sys.argv[2],
|
||||
k_AVERS: int(sys.argv[3]),
|
||||
k_GVERS: sys.argv[4],
|
||||
k_GVERS: sys.argv[3],
|
||||
}
|
||||
print getApp( params )
|
||||
print getApp( params, sys.argv[2] )
|
||||
elif arg == '--test-get-dicts':
|
||||
if not 5 == len(sys.argv): usage()
|
||||
if not 5 == argc: usage()
|
||||
params = { k_NAME: sys.argv[2],
|
||||
k_LANG : sys.argv[3],
|
||||
k_MD5SUM : sys.argv[4],
|
||||
|
@ -563,12 +604,19 @@ def main():
|
|||
}
|
||||
print getDicts( [params] )
|
||||
elif arg == '--list-apks':
|
||||
argc = len(sys.argv)
|
||||
if argc >= 4: usage()
|
||||
path = ""
|
||||
if argc >= 3: path = sys.argv[2]
|
||||
apks = getOrderedApks( path, False )
|
||||
if 0 == len(apks): print "No apks in", path
|
||||
debug = False
|
||||
appID = ''
|
||||
args = sys.argv[2:]
|
||||
while len(args):
|
||||
arg = args.pop(0)
|
||||
if arg == '--appID': appID = args.pop(0)
|
||||
elif arg == '--debug': debug = True
|
||||
elif arg == '--path': path = args.pop(0)
|
||||
if not appID: usage('--appID not optional')
|
||||
apks = getOrderedApks( path, appID, debug )
|
||||
if not len(apks): print "No apks in", path
|
||||
else: print
|
||||
for apk in apks:
|
||||
print apk
|
||||
elif arg == '--opponent-ids-for':
|
||||
|
|
|
@ -80,6 +80,24 @@ class GitRepo:
|
|||
break
|
||||
return result;
|
||||
|
||||
def getAllRevs( self ):
|
||||
result = []
|
||||
params = ['git', 'rev-list', '--reverse', 'HEAD']
|
||||
out, err = self.__doProcess( params )
|
||||
if err: self.__error('error from getRevsBetween')
|
||||
result = None
|
||||
if out:
|
||||
result = out.splitlines()
|
||||
return result
|
||||
|
||||
def tagToRev(self, tag):
|
||||
result = None
|
||||
params = ['git', 'rev-list', '-n', '1', tag]
|
||||
out, err = self.__doProcess( params )
|
||||
if err: self.__error('error from getRevsBetween')
|
||||
if out: result = out.strip()
|
||||
return result
|
||||
|
||||
def getHeadRev( self ):
|
||||
return self.getRevsBetween( 'HEAD', 'HEAD' )[0]
|
||||
|
||||
|
|
Loading…
Reference in a new issue