Check-in [1e5315f4df]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:start NFC support in borg command, NDEF tags only, for now
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1e5315f4dfca5fa494e4f783f49ec8a79d9a2248
User & Date: chw 2016-12-02 19:13:13.727
Context
2016-12-03
09:57
improved NFC support wrt broadcast listener check-in: 18c4f81217 user: chw tags: trunk
2016-12-02
19:13
start NFC support in borg command, NDEF tags only, for now check-in: 1e5315f4df user: chw tags: trunk
09:00
repair Android onscreen keyboard handling (broken since [b46b660d5e]) check-in: ebc1f80f21 user: chw tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to AndroidManifest.xml.
89
90
91
92
93
94
95



96
97
98
99
100
101
102

  <!-- USB support -->
  <uses-feature android:name="android.hardware.usb.host" />

  <!-- Don't require touchscreen -->
  <uses-feature android:name="android.hardware.touchscreen" required="false" />




  <!-- Disable screen compatibility modes -->
  <supports-screens android:smallScreens="true"
                    android:normalScreens="true"
                    android:largeScreens="true"
                    android:xlargeScreens="true" />

  <!-- Permissions: allow writing to external storage etc. -->







>
>
>







89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

  <!-- USB support -->
  <uses-feature android:name="android.hardware.usb.host" />

  <!-- Don't require touchscreen -->
  <uses-feature android:name="android.hardware.touchscreen" required="false" />

  <!-- Don't require NFC -->
  <uses-feature android:name="android.hardware.nfc" required="false" />

  <!-- Disable screen compatibility modes -->
  <supports-screens android:smallScreens="true"
                    android:normalScreens="true"
                    android:largeScreens="true"
                    android:xlargeScreens="true" />

  <!-- Permissions: allow writing to external storage etc. -->
126
127
128
129
130
131
132

133
    <uses-permission android:name="android.permission.SEND_SMS" />
  -->
  <!-- Uncomment this for "borg broadcast register android.provider.telephony.SMS_RECEIVED ..."
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
  -->
  <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
  <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />

</manifest>







>

129
130
131
132
133
134
135
136
137
    <uses-permission android:name="android.permission.SEND_SMS" />
  -->
  <!-- Uncomment this for "borg broadcast register android.provider.telephony.SMS_RECEIVED ..."
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
  -->
  <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
  <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />
  <uses-permission android:name="android.permission.NFC" />
</manifest>
Changes to jni/src/tkBorg.c.
142
143
144
145
146
147
148



149
150
151
152
153
154
155
static jmethodID M_AW_cameraGetImage = NULL;
static jmethodID M_AW_cameraGetState = NULL;
static jmethodID M_AW_cameraTakePicture = NULL;
static jmethodID M_AW_cameraGetPicture = NULL;
static jmethodID M_AW_checkPermission = NULL;
static jmethodID M_AW_osenvGetString = NULL;
static jmethodID M_AW_osenvGetFlag = NULL;




/* List of tk.tcl.wish.AndroWish static method descriptions */

static const struct {
    const char *name;
    const char *sig;
    jmethodID *midp;







>
>
>







142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
static jmethodID M_AW_cameraGetImage = NULL;
static jmethodID M_AW_cameraGetState = NULL;
static jmethodID M_AW_cameraTakePicture = NULL;
static jmethodID M_AW_cameraGetPicture = NULL;
static jmethodID M_AW_checkPermission = NULL;
static jmethodID M_AW_osenvGetString = NULL;
static jmethodID M_AW_osenvGetFlag = NULL;
static jmethodID M_AW_ndefRead = NULL;
static jmethodID M_AW_ndefWrite = NULL;
static jmethodID M_AW_ndefFormat = NULL;

/* List of tk.tcl.wish.AndroWish static method descriptions */

static const struct {
    const char *name;
    const char *sig;
    jmethodID *midp;
471
472
473
474
475
476
477















478
479
480
481
482
483
484
	"(ILjava/lang/String;)Ljava/lang/String;",
	&M_AW_osenvGetString
    },
    {
	"osenvGetFlag",
	"(I)I",
	&M_AW_osenvGetFlag















    }
};

/* List of tk.tcl.wish.WrappedCursor static method descriptions */

static const struct {
    const char *name;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
	"(ILjava/lang/String;)Ljava/lang/String;",
	&M_AW_osenvGetString
    },
    {
	"osenvGetFlag",
	"(I)I",
	&M_AW_osenvGetFlag
    },
    {
	"ndefRead",
	"(Ljava/lang/String;I)[Ljava/lang/String;",
	&M_AW_ndefRead
    },
    {
	"ndefWrite",
	"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
	&M_AW_ndefWrite
    },
    {
	"ndefFormat",
	"(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
	&M_AW_ndefFormat
    }
};

/* List of tk.tcl.wish.WrappedCursor static method descriptions */

static const struct {
    const char *name;
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
4847
4848
4849
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
    int ret, command;
    static CONST char *CONST borgCmds[] = {
	"activity", "alarm", "beep", "bluetooth",
	"brightness", "broadcast", "camera", "cancel",
	"checkpermission",
	"content", "displaymetrics", "endspeak", "isspeaking",
	"keyboardinfo", "locale", "location", "log",
	"networkinfo",
	"notification", "onintent", "osbuildinfo",
	"osenvironment", "packageinfo", "phoneinfo", "providerinfo",
	"queryactivities", "querybroadcastreceivers",
	"queryconsts", "queryfeatures", "queryfields",
	"queryservices",
	"screenorientation", "sendsms", "sensor", "shortcut",
	"speak", "speechrecognition", "spinner", "stopspeak",
	"systemproperties", "systemui", "tetherinfo", "toast",
	"trace", "usbdevices", "usbpermission", "vibrate",
	"withdraw", NULL
    };
    enum borgCommands {
	BORG_activity, BORG_alarm, BORG_beep, BORG_bluetooth,
	BORG_brightness, BORG_broadcast, BORG_camera, BORG_cancel,
	BORG_checkpermission,
	BORG_content, BORG_displaymetrics, BORG_endspeak, BORG_isspeaking,
	BORG_keyboardinfo, BORG_locale, BORG_location, BORG_log,
	BORG_networkinfo,
	BORG_notification, BORG_onintent, BORG_osbuildinfo,
	BORG_osenvironment, BORG_packageinfo, BORG_phoneinfo, BORG_providerinfo,
	BORG_queryactivities, BORG_querybroadcastreceivers,
	BORG_queryconsts, BORG_queryfeatures, BORG_queryfields,
	BORG_queryservices,
	BORG_screenorientation, BORG_sendsms, BORG_sensor, BORG_shortcut,
	BORG_speak, BORG_speechrecognition, BORG_spinner, BORG_stopspeak,







|

















|







4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
4868
4869
4870
4871
4872
4873
4874
4875
4876
4877
4878
4879
4880
4881
4882
4883
4884
    int ret, command;
    static CONST char *CONST borgCmds[] = {
	"activity", "alarm", "beep", "bluetooth",
	"brightness", "broadcast", "camera", "cancel",
	"checkpermission",
	"content", "displaymetrics", "endspeak", "isspeaking",
	"keyboardinfo", "locale", "location", "log",
	"ndefformat", "ndefread", "ndefwrite", "networkinfo",
	"notification", "onintent", "osbuildinfo",
	"osenvironment", "packageinfo", "phoneinfo", "providerinfo",
	"queryactivities", "querybroadcastreceivers",
	"queryconsts", "queryfeatures", "queryfields",
	"queryservices",
	"screenorientation", "sendsms", "sensor", "shortcut",
	"speak", "speechrecognition", "spinner", "stopspeak",
	"systemproperties", "systemui", "tetherinfo", "toast",
	"trace", "usbdevices", "usbpermission", "vibrate",
	"withdraw", NULL
    };
    enum borgCommands {
	BORG_activity, BORG_alarm, BORG_beep, BORG_bluetooth,
	BORG_brightness, BORG_broadcast, BORG_camera, BORG_cancel,
	BORG_checkpermission,
	BORG_content, BORG_displaymetrics, BORG_endspeak, BORG_isspeaking,
	BORG_keyboardinfo, BORG_locale, BORG_location, BORG_log,
	BORG_ndefformat, BORG_ndefread, BORG_ndefwrite, BORG_networkinfo,
	BORG_notification, BORG_onintent, BORG_osbuildinfo,
	BORG_osenvironment, BORG_packageinfo, BORG_phoneinfo, BORG_providerinfo,
	BORG_queryactivities, BORG_querybroadcastreceivers,
	BORG_queryconsts, BORG_queryfeatures, BORG_queryfields,
	BORG_queryservices,
	BORG_screenorientation, BORG_sendsms, BORG_sensor, BORG_shortcut,
	BORG_speak, BORG_speechrecognition, BORG_spinner, BORG_stopspeak,
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5660
5661
5662
5663
5664
5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
    case BORG_usbdevices: {
	int ext = 0;

	if (objc > 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?extended?");
	    return TCL_ERROR;
	}
	if ((objc > 2) && 
	    (Tcl_GetBooleanFromObj(interp, objv[2], &ext) != TCL_OK)) {
	    return TCL_ERROR;
	}
	return UsbDevices(interp, ext);
    }

    case BORG_usbpermission: {
	int ask = 0;

	if ((objc < 3) || (objc > 4)) {
	    Tcl_WrongNumArgs(interp, 2, objv, "device ?ask?");
	    return TCL_ERROR;
	}
	if ((objc > 3) && 
	    (Tcl_GetBooleanFromObj(interp, objv[3], &ask) != TCL_OK)) {
	    return TCL_ERROR;
	}
	return UsbPermission(interp, Tcl_GetString(objv[2]), ask);
    }

    case BORG_toast: {







|













|







5665
5666
5667
5668
5669
5670
5671
5672
5673
5674
5675
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
    case BORG_usbdevices: {
	int ext = 0;

	if (objc > 3) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?extended?");
	    return TCL_ERROR;
	}
	if ((objc > 2) &&
	    (Tcl_GetBooleanFromObj(interp, objv[2], &ext) != TCL_OK)) {
	    return TCL_ERROR;
	}
	return UsbDevices(interp, ext);
    }

    case BORG_usbpermission: {
	int ask = 0;

	if ((objc < 3) || (objc > 4)) {
	    Tcl_WrongNumArgs(interp, 2, objv, "device ?ask?");
	    return TCL_ERROR;
	}
	if ((objc > 3) &&
	    (Tcl_GetBooleanFromObj(interp, objv[3], &ask) != TCL_OK)) {
	    return TCL_ERROR;
	}
	return UsbPermission(interp, Tcl_GetString(objv[2]), ask);
    }

    case BORG_toast: {
6271
6272
6273
6274
6275
6276
6277




6278
6279
6280
6281
6282
6283
6284
	    OSENV_isexternalstorageremovable,
	    OSENV_rootdir
	};
	int op;
	JNIEnv *env = GetJNIEnv();
	jstring jstr = NULL, jret = NULL;





	if ((objc < 3) || (objc > 4)) {
	    Tcl_WrongNumArgs(interp, 2, objv, "datadir|rootdir|... ?path?");
	    return TCL_ERROR;
	}
	if (Tcl_GetIndexFromObj(interp, objv[2], osenvCmds, "option",
				0, &command) != TCL_OK) {
	    return TCL_ERROR;







>
>
>
>







6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
6300
6301
6302
6303
6304
6305
6306
	    OSENV_isexternalstorageremovable,
	    OSENV_rootdir
	};
	int op;
	JNIEnv *env = GetJNIEnv();
	jstring jstr = NULL, jret = NULL;

	if (env == NULL) {
	    Tcl_SetResult(interp, "no JNIEnv", TCL_STATIC);
	    return TCL_ERROR;
	}
	if ((objc < 3) || (objc > 4)) {
	    Tcl_WrongNumArgs(interp, 2, objv, "datadir|rootdir|... ?path?");
	    return TCL_ERROR;
	}
	if (Tcl_GetIndexFromObj(interp, objv[2], osenvCmds, "option",
				0, &command) != TCL_OK) {
	    return TCL_ERROR;
6326
6327
6328
6329
6330
6331
6332
6333
6334
6335
6336
6337
6338



























































































6339
6340
6341
6342
6343
6344
6345
	case OSENV_isexternalstorageremovable:
	    op = 1;
	oseGetFlag:
	    op = (*env)->CallStaticIntMethod(env, jactivity,
					     M_AW_osenvGetFlag, op);
	    Tcl_SetObjResult(interp, Tcl_NewIntObj(op));
	    break;
	}	
	if (jstr != NULL) {
	    (*env)->DeleteLocalRef(env, jstr);
	}
	return ret;
    }




























































































    }

    return TCL_OK;
}

JNIEnv *







|





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







6348
6349
6350
6351
6352
6353
6354
6355
6356
6357
6358
6359
6360
6361
6362
6363
6364
6365
6366
6367
6368
6369
6370
6371
6372
6373
6374
6375
6376
6377
6378
6379
6380
6381
6382
6383
6384
6385
6386
6387
6388
6389
6390
6391
6392
6393
6394
6395
6396
6397
6398
6399
6400
6401
6402
6403
6404
6405
6406
6407
6408
6409
6410
6411
6412
6413
6414
6415
6416
6417
6418
6419
6420
6421
6422
6423
6424
6425
6426
6427
6428
6429
6430
6431
6432
6433
6434
6435
6436
6437
6438
6439
6440
6441
6442
6443
6444
6445
6446
6447
6448
6449
6450
6451
6452
6453
6454
6455
6456
6457
6458
	case OSENV_isexternalstorageremovable:
	    op = 1;
	oseGetFlag:
	    op = (*env)->CallStaticIntMethod(env, jactivity,
					     M_AW_osenvGetFlag, op);
	    Tcl_SetObjResult(interp, Tcl_NewIntObj(op));
	    break;
	}
	if (jstr != NULL) {
	    (*env)->DeleteLocalRef(env, jstr);
	}
	return ret;
    }

    case BORG_ndefread: {
	JNIEnv *env = GetJNIEnv();
	jstring jtag = NULL;
	jobjectArray jret = NULL, jstr;
	int len, cached = 0;

	if (env == NULL) {
	    Tcl_SetResult(interp, "no JNIEnv", TCL_STATIC);
	    return TCL_ERROR;
	}
	if ((objc < 3) || (objc > 4)) {
	    Tcl_WrongNumArgs(interp, 2, objv, "tag ?cached?");
	    return TCL_ERROR;
	}
	if ((objc > 3) &&
	    (Tcl_GetBooleanFromObj(interp, objv[3], &cached) != TCL_OK)) {
	    return TCL_ERROR;
	}
	jtag = (*env)->NewStringUTF(env, Tcl_GetString(objv[2]));
	jret = (*env)->CallStaticObjectMethod(env, jactivity,
					      M_AW_ndefRead, jtag,
					      (jint) cached);
	(*env)->ExceptionClear(env);
	(*env)->DeleteLocalRef(env, jtag);
	if (jret == NULL) {
	    Tcl_SetResult(interp, "unknown error", TCL_STATIC);
	    return TCL_ERROR;
	}
	len = (*env)->GetArrayLength(env, jret);
	if (len < 2) {
	    (*env)->DeleteLocalRef(env, jret);
	    Tcl_SetResult(interp, "unknown error", TCL_STATIC);
	    return TCL_ERROR;
	}
	jstr = (*env)->GetObjectArrayElement(env, jret, 0);
	if (jstr != NULL) {
	    const char *str = (*env)->GetStringUTFChars(env, jstr, 0);

	    Tcl_SetObjResult(interp, Tcl_NewStringObj(str, -1));
	    (*env)->ReleaseStringUTFChars(env, jstr, str);
	    (*env)->DeleteLocalRef(env, jstr);
	    (*env)->DeleteLocalRef(env, jret);
	    return TCL_ERROR;
	}
	jstr = (*env)->GetObjectArrayElement(env, jret, 1);
	if (jstr != NULL) {
	    const char *str = (*env)->GetStringUTFChars(env, jstr, 0);

	    Tcl_SetObjResult(interp, Tcl_NewStringObj(str, -1));
	    (*env)->ReleaseStringUTFChars(env, jstr, str);
	    (*env)->DeleteLocalRef(env, jstr);
	} else {
	    Tcl_SetObjResult(interp, Tcl_NewObj());
	}
	(*env)->DeleteLocalRef(env, jret);
	return TCL_OK;
    }

    case BORG_ndefwrite:
    case BORG_ndefformat: {
	JNIEnv *env = GetJNIEnv();
	jstring jtag = NULL, jdata = NULL, jret = NULL;

	if (env == NULL) {
	    Tcl_SetResult(interp, "no JNIEnv", TCL_STATIC);
	    return TCL_ERROR;
	}
	if (objc != 4) {
	    Tcl_WrongNumArgs(interp, 2, objv, "tag ndefdata");
	    return TCL_ERROR;
	}
	jtag = (*env)->NewStringUTF(env, Tcl_GetString(objv[2]));
	jdata = (*env)->NewStringUTF(env, Tcl_GetString(objv[3]));
	jret = (*env)->CallStaticObjectMethod(env, jactivity,
					      (command == BORG_ndefformat) ?
					      M_AW_ndefFormat : M_AW_ndefWrite,
					      jtag, jdata);
	(*env)->ExceptionClear(env);
	(*env)->DeleteLocalRef(env, jtag);
	(*env)->DeleteLocalRef(env, jdata);
	if (jret != NULL) {
	    const char *str = (*env)->GetStringUTFChars(env, jret, 0);

	    Tcl_SetObjResult(interp, Tcl_NewStringObj(str, -1));
	    (*env)->ReleaseStringUTFChars(env, jret, str);
	    (*env)->DeleteLocalRef(env, jret);
	    return TCL_ERROR;
	}
	return TCL_OK;
    }

    }

    return TCL_OK;
}

JNIEnv *
Changes to src/tk/tcl/wish/AndroWish.java.
38
39
40
41
42
43
44


45
46
47
48
49
50
51
import android.util.*;
import android.bluetooth.*;
import android.widget.*;
import android.support.v4.app.NotificationCompat;
import android.hardware.*;
import android.hardware.usb.*;
import android.telephony.*;



public class AndroWish extends SDLActivity implements LocationListener {

    static final String TAG = "AndroWish";

    protected static AndroWish mSingleton;
    protected static PackageManager mPackageManager;







>
>







38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import android.util.*;
import android.bluetooth.*;
import android.widget.*;
import android.support.v4.app.NotificationCompat;
import android.hardware.*;
import android.hardware.usb.*;
import android.telephony.*;
import android.nfc.*;
import android.nfc.tech.*;

public class AndroWish extends SDLActivity implements LocationListener {

    static final String TAG = "AndroWish";

    protected static AndroWish mSingleton;
    protected static PackageManager mPackageManager;
76
77
78
79
80
81
82


83
84
85
86
87
88
89
    protected static NmeaInfo mNmeaInfo;
    protected static TelephonyManager mPhoneManager;
    protected static PSListener mPSListener;
    protected static Map<String, BCRecvr> mBCRecvrs;
    protected static ImageCapture mCamera;
    protected static BroadcastReceiver mUsbRecvr;
    protected static Map<String, UsbDeviceConnection> mUsbHold;



    /*
     * Callback on application startup
     */

    @Override
    public void onCreate(Bundle savedInstanceData) {







>
>







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
    protected static NmeaInfo mNmeaInfo;
    protected static TelephonyManager mPhoneManager;
    protected static PSListener mPSListener;
    protected static Map<String, BCRecvr> mBCRecvrs;
    protected static ImageCapture mCamera;
    protected static BroadcastReceiver mUsbRecvr;
    protected static Map<String, UsbDeviceConnection> mUsbHold;
    protected static NfcAdapter mNfcAdapter;
    protected static Tag mNfcTag;

    /*
     * Callback on application startup
     */

    @Override
    public void onCreate(Bundle savedInstanceData) {
254
255
256
257
258
259
260








261
262
263
264
265
266
267
			    }
			}
		    }
		}
	    };
	    registerReceiver(mUsbRecvr, filter);
	}








    }

    /*
     * Tear down everything
     */

    @Override







>
>
>
>
>
>
>
>







258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
			    }
			}
		    }
		}
	    };
	    registerReceiver(mUsbRecvr, filter);
	}
	if (hasPerm(android.Manifest.permission.NFC)) {
	    NfcManager manager =
		(NfcManager) getSystemService(Context.NFC_SERVICE);
	    mNfcAdapter = manager.getDefaultAdapter();
	} else {
	    mNfcAdapter = null;
	}
	mNfcTag = null;
    }

    /*
     * Tear down everything
     */

    @Override
318
319
320
321
322
323
324




325
326
327
328
329
330
331
	if (mUsbHold != null) {
	    for (final UsbDeviceConnection c : mUsbHold.values()) {
		c.close();
	    }
	    mUsbHold.clear();
	    mUsbHold = null;
	}




    }

    /*
     * Find out if OpenGL ES >= 2.x is available.
     */

    private static int getGLESVersion(Context context) {







>
>
>
>







330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
	if (mUsbHold != null) {
	    for (final UsbDeviceConnection c : mUsbHold.values()) {
		c.close();
	    }
	    mUsbHold.clear();
	    mUsbHold = null;
	}
	if (mNfcAdapter != null) {
	    mNfcAdapter.disableForegroundDispatch(this);
	}
	mNfcTag = null;
    }

    /*
     * Find out if OpenGL ES >= 2.x is available.
     */

    private static int getGLESVersion(Context context) {
355
356
357
358
359
360
361




362
363
364
365
366
367
368
	mSensors.pause();
	if (mPSListener != null) {
	    mPhoneManager.listen(mPSListener, PhoneStateListener.LISTEN_NONE);
	}
	if (mCamera != null) {
	    mCamera.onPause();
	}




    }

    @Override
    public void onResume() {
	super.onResume();
	mSensors.resume();
	if (mPSListener != null) {







>
>
>
>







371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
	mSensors.pause();
	if (mPSListener != null) {
	    mPhoneManager.listen(mPSListener, PhoneStateListener.LISTEN_NONE);
	}
	if (mCamera != null) {
	    mCamera.onPause();
	}
	if (mNfcAdapter != null) {
	    mNfcAdapter.disableForegroundDispatch(this);
	}
	mNfcTag = null;
    }

    @Override
    public void onResume() {
	super.onResume();
	mSensors.resume();
	if (mPSListener != null) {
384
385
386
387
388
389
390






















391
392
393
394
395
396
397
	    }
	}
	if (trigger) {
	    mSingleton.nativeTriggerKeyboard();
	}
	if (mCamera != null) {
	    mCamera.onResume();






















	}
    }

    /*
     * Configuration (e.g. keyboard) has changed
     */








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
	    }
	}
	if (trigger) {
	    mSingleton.nativeTriggerKeyboard();
	}
	if (mCamera != null) {
	    mCamera.onResume();
	}
	if (mNfcAdapter != null) {
	    PendingIntent pi =
		PendingIntent.getBroadcast(getContext(), 0,
					   new Intent("tk.tcl.wish.nfc"), 0);
	    /*
	     * This should be sufficient but doesn't work, unfortunately:
	     *
	     *   mNfcAdapter.enableForegroundDispatch(this, pi, null, null);
	     *
	     * thus use filters for both intent and tech.
	     */

	    IntentFilter ndef =
		new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
	    IntentFilter[] filt = new IntentFilter[] { ndef };
	    String[][] techs = new String[][] {
		new String[] { Ndef.class.getName() },
		new String[] { NdefFormatable.class.getName() }
	    };
	    mNfcAdapter.enableForegroundDispatch(this, pi, filt, techs);
	    mNfcTag = null;
	}
    }

    /*
     * Configuration (e.g. keyboard) has changed
     */

460
461
462
463
464
465
466















467
468
469
470
471
472
473
		ret[k] = encodeLongList((long []) obj);
	    } else if (obj instanceof boolean[]) {
		ret[k] = encodeBoolList((boolean []) obj);
	    } else if (obj instanceof char[]) {
		ret[k] = encodeCharList((char []) obj);
	    } else if (obj instanceof Boolean) {
		ret[k] = ((Boolean) obj).booleanValue() ? "1" : "0";















	    } else {
		ret[k] = obj.toString();
	    }
	    k++;
	}
	if (add != null) {
	    for (int i = 0; i < add.length; i++) {







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
		ret[k] = encodeLongList((long []) obj);
	    } else if (obj instanceof boolean[]) {
		ret[k] = encodeBoolList((boolean []) obj);
	    } else if (obj instanceof char[]) {
		ret[k] = encodeCharList((char []) obj);
	    } else if (obj instanceof Boolean) {
		ret[k] = ((Boolean) obj).booleanValue() ? "1" : "0";
	    } else if ((obj instanceof Parcelable[]) &&
		       key.equals(NfcAdapter.EXTRA_NDEF_MESSAGES)) {
		ArrayList<byte[]> al = new ArrayList<byte[]>();
		Parcelable[] pa = (Parcelable[]) obj;
		for (int n = 0; n < pa.length; n++) {
		    NdefMessage msg = (NdefMessage) pa[n];
		    byte[] ba;
		    if (msg != null) {
			ba = msg.toByteArray();
		    } else {
			ba = new byte[0];
		    }
		    al.add(ba);
		}
		ret[k] = encodeToList(al);
	    } else {
		ret[k] = obj.toString();
	    }
	    k++;
	}
	if (add != null) {
	    for (int i = 0; i < add.length; i++) {
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
     */

    public static int getResourceId(String name, String res) {
	try {
	    return mSingleton.getResources().getIdentifier(name, res, mSingleton.getPackageName());
	} catch (Exception e) {
	    return -1;
	} 
    }

    /*
     * Callback to deal with activity results
     */

    @Override







|







613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
     */

    public static int getResourceId(String name, String res) {
	try {
	    return mSingleton.getResources().getIdentifier(name, res, mSingleton.getPackageName());
	} catch (Exception e) {
	    return -1;
	}
    }

    /*
     * Callback to deal with activity results
     */

    @Override
713
714
715
716
717
718
719


720
721
722
723
724
725
726
	    if (i != 0) {
		r.append(" ");
	    }
	    if (obj == null) {
		r.append("{}");
	    } else if (obj instanceof String) {
		r.append(toElement((String) obj));


	    } else {
		r.append(toElement(obj.toString()));
	    }
	}
	return r.toString();
    }








>
>







770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
	    if (i != 0) {
		r.append(" ");
	    }
	    if (obj == null) {
		r.append("{}");
	    } else if (obj instanceof String) {
		r.append(toElement((String) obj));
	    } else if (obj instanceof byte[]) {
		r.append(Base64.encodeToString((byte[]) obj, Base64.DEFAULT));
	    } else {
		r.append(toElement(obj.toString()));
	    }
	}
	return r.toString();
    }

935
936
937
938
939
940
941
942

943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961



962
963
964
965
966
967
968
969
970
971
	String uristr = i.getDataString();
	String type = i.getType();
	String[] cats = null;
	String[] args = null;
	if (i.getCategories() != null) {
	    cats = formatCategories(i.getCategories());
	}
	if (i.getExtras() != null) {

	    String addargs[] = null;
	    if (action.equals("android.provider.Telephony.SMS_RECEIVED")) {
		Bundle b = i.getExtras();
		if (b != null) {
		    Object[] pdus = (Object[]) b.get("pdus");
		    if (pdus.length > 0) {
			SmsMessage[] msgs = new SmsMessage[pdus.length];
			StringBuilder sb = new StringBuilder();
			for (int k = 0; k < pdus.length; k++) {
			    msgs[k] =
				SmsMessage.createFromPdu((byte[]) pdus[k]);
			    sb.append(msgs[k].getMessageBody());
			}
			addargs = new String[4];
			addargs[0] = "phone_number";
			addargs[1] = msgs[0].getOriginatingAddress();
			addargs[2] = "sms_text";
			addargs[3] = sb.toString();
		    }



		}
            }
	    args = formatBundle(i.getExtras(), addargs);
	}
	Log.v(TAG, "nativeBroadcastCallback: " + retcode + "," + action +
	      "," + uristr + "," + type + "," + cats + "," + args);
	nativeBroadcastCallback(retcode, action, uristr, type, cats, args);
    }

    /*







|
>


<
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>

|
|







994
995
996
997
998
999
1000
1001
1002
1003
1004


1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
	String uristr = i.getDataString();
	String type = i.getType();
	String[] cats = null;
	String[] args = null;
	if (i.getCategories() != null) {
	    cats = formatCategories(i.getCategories());
	}
	Bundle extras = i.getExtras();
	if (extras != null) {
	    String addargs[] = null;
	    if (action.equals("android.provider.Telephony.SMS_RECEIVED")) {


		Object[] pdus = (Object[]) extras.get("pdus");
		if (pdus.length > 0) {
		    SmsMessage[] msgs = new SmsMessage[pdus.length];
		    StringBuilder sb = new StringBuilder();
		    for (int k = 0; k < pdus.length; k++) {
			msgs[k] =
			    SmsMessage.createFromPdu((byte[]) pdus[k]);
			sb.append(msgs[k].getMessageBody());
		    }
		    addargs = new String[4];
		    addargs[0] = "phone_number";
		    addargs[1] = msgs[0].getOriginatingAddress();
		    addargs[2] = "sms_text";
		    addargs[3] = sb.toString();
		}
            } else if (action.equals("tk.tcl.wish.nfc")) {
		if (extras.get(NfcAdapter.EXTRA_TAG) != null) {
		    mNfcTag = (Tag) extras.get(NfcAdapter.EXTRA_TAG);
		}
	    }
	    args = formatBundle(extras, addargs);
	}
	Log.v(TAG, "nativeBroadcastCallback: " + retcode + "," + action +
	      "," + uristr + "," + type + "," + cats + "," + args);
	nativeBroadcastCallback(retcode, action, uristr, type, cats, args);
    }

    /*
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
		if (uristr != null) {
		    if (uristr.length() == 0) {
			return;
		    }
		    ringuri = Uri.parse(uristr);
		}
		if (ringuri == null) {
		    ringuri = 
			RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
		}
		Ringtone tone =
		    RingtoneManager.getRingtone(mSingleton.getBaseContext(),
						ringuri);
		if ((tone != null) && (!tone.isPlaying())) {
		    tone.play();







|







1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
		if (uristr != null) {
		    if (uristr.length() == 0) {
			return;
		    }
		    ringuri = Uri.parse(uristr);
		}
		if (ringuri == null) {
		    ringuri =
			RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
		}
		Ringtone tone =
		    RingtoneManager.getRingtone(mSingleton.getBaseContext(),
						ringuri);
		if ((tone != null) && (!tone.isPlaying())) {
		    tone.play();
1865
1866
1867
1868
1869
1870
1871


1872



1873
1874
1875
1876
1877
1878
1879
	    if (android.os.Build.VERSION.SDK_INT < 14) {
		toRun.putExtra("arg", arg);
	    } else {
		toRun.setData(Uri.parse(arg));
	    }
	}
	if (icon != null) {


	    byte b[] = Base64.decode(icon, Base64.DEFAULT);



	    if ((b != null) && (b.length > 0)) {
		iconBitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
	    }
	}
	switch (op) {
	case 0:		/* add */
	    shortcut = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");







>
>
|
>
>
>







1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
	    if (android.os.Build.VERSION.SDK_INT < 14) {
		toRun.putExtra("arg", arg);
	    } else {
		toRun.setData(Uri.parse(arg));
	    }
	}
	if (icon != null) {
	    byte b[];
	    try {
		b = Base64.decode(icon, Base64.DEFAULT);
	    } catch (Exception be) {
		b = null;
	    }
	    if ((b != null) && (b.length > 0)) {
		iconBitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
	    }
	}
	switch (op) {
	case 0:		/* add */
	    shortcut = new Intent("com.android.launcher.action.INSTALL_SHORTCUT");
1944
1945
1946
1947
1948
1949
1950


1951



1952
1953
1954
1955
1956
1957
1958
		break;
	    }
	    nb = new NotificationCompat.Builder(mSingleton.getContext());
	    nb.setSmallIcon(R.drawable.icon);
	    nb.setContentTitle(title);
	    nb.setContentText(text);
	    if (icon != null) {


		byte b[] = Base64.decode(icon, Base64.DEFAULT);



		if ((b != null) && (b.length > 0)) {
		    Bitmap iconBitmap =
			BitmapFactory.decodeByteArray(b, 0, b.length);
		    nb.setLargeIcon(iconBitmap);
		}
	    }
	    nb.setContentIntent(pi);







>
>
|
>
>
>







2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
		break;
	    }
	    nb = new NotificationCompat.Builder(mSingleton.getContext());
	    nb.setSmallIcon(R.drawable.icon);
	    nb.setContentTitle(title);
	    nb.setContentText(text);
	    if (icon != null) {
		byte b[];
		try {
		    b = Base64.decode(icon, Base64.DEFAULT);
		} catch (Exception be) {
		    b = null;
		}
		if ((b != null) && (b.length > 0)) {
		    Bitmap iconBitmap =
			BitmapFactory.decodeByteArray(b, 0, b.length);
		    nb.setLargeIcon(iconBitmap);
		}
	    }
	    nb.setContentIntent(pi);
2738
2739
2740
2741
2742
2743
2744






















































































































































































2745
2746
2747
2748
2749
2750
2751
	    break;
	case 1:
	    b = android.os.Environment.isExternalStorageRemovable();
	    break;
	}
	return b ? 1 : 0;
    }























































































































































































    /*
     * Native setenv
     */

    public static native int nativeSetenv(String name, String value);








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
	    break;
	case 1:
	    b = android.os.Environment.isExternalStorageRemovable();
	    break;
	}
	return b ? 1 : 0;
    }

    /*
     * NFC related: read/write NDEF content to tag.
     */

    public static String[] ndefRead(String tagstr, int cached) {
	String result[] = new String[2];
	Tag tag = mNfcTag;
	byte tb[] = null;
	result[0] = "unknown error";
	result[1] = null;
	try {
	    tb = Base64.decode(tagstr, Base64.DEFAULT);
	} catch (Exception te) {
	    tb = null;
	}
	if (tb == null) {
	    result[0] = "tag invalid";
	    Log.e(TAG, "ndefRead: " + result[0]);
	    return result;
	}
	if (tag == null) {
	    result[0] = "no current tag";
	    Log.e(TAG, "nfcRead: " + result[0]);
	    return result;
	}
	if (!Arrays.equals(tag.getId(), tb)) {
	    result[0] = "wrong tag id";
	    Log.e(TAG, "nfcRead: tag not current: " + tagstr + " expecting " +
		  Base64.encodeToString(tag.getId(), Base64.DEFAULT));
	    return result;
	}
	try {
	    Ndef ndef = Ndef.get(tag);
	    NdefMessage ndmsg;
	    if (cached == 0) {
		ndef.connect();
		ndmsg = ndef.getNdefMessage();
		ndef.close();
	    } else {
		ndmsg = ndef.getCachedNdefMessage();
	    }
	    if (ndmsg != null) {
		result[1] =
		    Base64.encodeToString(ndmsg.toByteArray(), Base64.DEFAULT);
	    }
	} catch (Exception e) {
	    result[0] = "read error";
	    result[1] = null;
	    Log.e(TAG, "nfcRead: exception: " + e.toString());
	    return result;
	}
	result[0] = null;
	return result;
    }

    public static String ndefWrite(String tagstr, String msg) {
	Tag tag = mNfcTag;
	byte tb[];
	try {
	    tb = Base64.decode(tagstr, Base64.DEFAULT);
	} catch (Exception te) {
	    tb = null;
	}
	if (tb == null) {
	    Log.e(TAG, "ndefWrite: tag invalid");
	    return "tag invalid";
	}
	byte mb[];
	try {
	    mb = Base64.decode(msg, Base64.DEFAULT);
	} catch (Exception me) {
	    mb = null;
	}
	if (mb == null) {
	    Log.e(TAG, "ndefWrite: message invalid");
	    return "message invalid";
	}
	if (tag == null) {
	    Log.e(TAG, "ndefWrite: no current tag");
	    return "no current tag";
	}
	if (!Arrays.equals(tag.getId(), tb)) {
	    Log.e(TAG, "ndefWrite: tag not current: " + tagstr + " expecting " +
		  Base64.encodeToString(tag.getId(), Base64.DEFAULT));
	    return "wrong tag id";
	}
	try {
	    NdefMessage ndmsg = new NdefMessage(mb);
	    int size = ndmsg.toByteArray().length;
	    Ndef ndef = Ndef.get(tag);
	    if (ndef == null) {
		NdefFormatable nfmt = NdefFormatable.get(tag);
		if (nfmt == null) {
		    Log.e(TAG, "ndefWrite: unsupported tech");
		    return "unsupported tech";
		}
		nfmt.connect();
		nfmt.format(ndmsg);
		nfmt.close();
	    } else {
		ndef.connect();
		if (!ndef.isWritable()) {
		    ndef.close();
		    Log.e(TAG, "ndefWrite: read only tag");
		    return "read only tag";
		}
		if (size > ndef.getMaxSize()) {
		    ndef.close();
		    Log.e(TAG, "ndefWrite: message too large (" + size + ">" +
			  ndef.getMaxSize() + ")");
		    return "message too large";
		}
		ndef.writeNdefMessage(ndmsg);
		ndef.close();
	    }
	} catch (FormatException fe) {
	    Log.e(TAG, "ndefWrite: format exception: " + fe.toString());
	    return "wrong ndef format";
	} catch (IOException ie) {
	    Log.e(TAG, "ndefWrite: I/O exception: " + ie.toString());
	    return "I/O error";
	} catch (Exception e) {
	    Log.e(TAG, "ndefWrite: other exception: " + e.toString());
	    return "unknown error";
	}
	return null;
    }

    public static String ndefFormat(String tagstr, String msg) {
	Tag tag = mNfcTag;
	byte tb[];
	try {
	    tb = Base64.decode(tagstr, Base64.DEFAULT);
	} catch (Exception te) {
	    tb = null;
	}
	if (tb == null) {
	    Log.e(TAG, "ndefFormat: tag invalid");
	    return "tag invalid";
	}
	byte mb[] = null;
	try {
	    mb = Base64.decode(msg, Base64.DEFAULT);
	} catch (Exception me) {
	    mb = null;
	}
	if (mb == null) {
	    Log.e(TAG, "ndefFormat: message invalid");
	    return "message invalid";
	}
	if (tag == null) {
	    Log.e(TAG, "ndefFormat: no current tag");
	    return "no current tag";
	}
	if (!Arrays.equals(tag.getId(), tb)) {
	    Log.e(TAG, "ndefFormat: tag not current: " + tagstr + " expecting " +
		  Base64.encodeToString(tag.getId(), Base64.DEFAULT));
	    return "wrong tag id";
	}
	try {
	    NdefFormatable nfmt = NdefFormatable.get(tag);
	    if (nfmt == null) {
		Log.e(TAG, "ndefFormat: unsupported tech");
		return "unsupported tech";
	    }
	    nfmt.connect();
	    NdefMessage ndmsg = new NdefMessage(mb);
	    nfmt.format(ndmsg);
	    nfmt.close();
	} catch (FormatException fe) {
	    Log.e(TAG, "ndefFormat: format exception: " + fe.toString());
	    return "wrong ndef format";
	} catch (IOException ie) {
	    Log.e(TAG, "ndefFormat: I/O exception: " + ie.toString());
	    return "I/O error";
	} catch (Exception e) {
	    Log.e(TAG, "ndefFormat: other exception: " + e.toString());
	    return "unknown error";
	}
	return null;
    }

    /*
     * Native setenv
     */

    public static native int nativeSetenv(String name, String value);