/android/export-contacts

To get this branch, use:
bzr branch http://bzr.ed.am/android/export-contacts
5 by edam
- added ContactReader interface
1
/*
2
 * Exporter.java
3
 *
4
 * Copyright (C) 2011 Tim Marston <edam@waxworlds.org>
5
 *
6
 * This file is part of the Export Contacts program (hereafter referred
7
 * to as "this program"). For more information, see
8
 * http://www.waxworlds.org/edam/software/android/export-contacts
9
 *
10
 * This program is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
 */
23
24
package org.waxworlds.edam.exportcontacts;
25
26
import java.util.ArrayList;
27
28
import android.content.SharedPreferences;
29
import android.os.Message;
30
31
32
public class Exporter extends Thread
33
{
34
	public final static int ACTION_ABORT = 1;
35
	public final static int ACTION_ALLDONE = 2;
36
37
	public final static int RESPONSE_NEGATIVE = 0;
38
	public final static int RESPONSE_POSITIVE = 1;
39
40
	public final static int RESPONSEEXTRA_NONE = 0;
41
	public final static int RESPONSEEXTRA_ALWAYS = 1;
42
43
	private Doit _doit;
44
	private int _response;
45
	private boolean _abort = false;
46
	private boolean _is_finished = false;
47
48
	/**
49
	 * Data about a contact
50
	 */
51
	public class ContactData
52
	{
53
		class OrganisationDetail
54
		{
55
			protected String _org;
56
			protected String _title;
57
58
			public OrganisationDetail( String org, String title )
59
			{
60
				_org = org != null && org.length() > 0? org : null;
61
				_title = title != null && title.length() > 0? title : null;
62
			}
63
64
			public String getOrganisation()
65
			{
66
				return _org;
67
			}
68
69
			public String getTitle()
70
			{
71
				return _title;
72
			}
73
		}
74
75
		class NumberDetail
76
		{
77
			protected int _type;
78
			protected String _num;
79
80
			public NumberDetail( int type, String num )
81
			{
82
				_type = type;
83
				_num = num != null && num.length() > 0? num : null;
84
			}
85
86
			public int getType()
87
			{
88
				return _type;
89
			}
90
91
			public String getNumber()
92
			{
93
				return _num;
94
			}
95
		}
96
97
		class EmailDetail
98
		{
99
			protected int _type;
100
			protected String _email;
101
102
			public EmailDetail( int type, String email )
103
			{
104
				_type = type;
105
				_email = email != null && email.length() > 0? email : null;
106
			}
107
108
			public int getType()
109
			{
110
				return _type;
111
			}
112
113
			public String getEmail()
114
			{
115
				return _email;
116
			}
117
		}
118
119
		class AddressDetail
120
		{
121
			protected int _type;
122
			protected String _addr;
123
124
			public AddressDetail( int type, String addr )
125
			{
126
				_type = type;
127
				_addr = addr != null && addr.length() > 0? addr : null;
128
			}
129
130
			public int getType()
131
			{
132
				return _type;
133
			}
134
135
			public String getAddress()
136
			{
137
				return _addr;
138
			}
139
		}
140
141
		protected String _name = null;
142
		protected ArrayList< OrganisationDetail > _organisations = null;
143
		protected ArrayList< NumberDetail > _numbers = null;
144
		protected ArrayList< EmailDetail > _emails = null;
145
		protected ArrayList< AddressDetail > _addresses = null;
146
147
		public void setName( String name )
148
		{
149
			_name = name != null && name.length() > 0? name : null;
150
		}
151
152
		public String getName()
153
		{
154
			return _name;
155
		}
156
157
		public void addOrganisation( OrganisationDetail organisation )
158
		{
159
			if( organisation.getOrganisation() == null ) return;
160
			if( _organisations == null )
161
				_organisations = new ArrayList< OrganisationDetail >();
162
			_organisations.add( organisation );
163
		}
164
165
		public ArrayList< OrganisationDetail > getOrganisations()
166
		{
167
			return _organisations;
168
		}
169
170
		public void addNumber( NumberDetail number )
171
		{
172
			if( number.getNumber() == null ) return;
173
			if( _numbers == null )
174
				_numbers = new ArrayList< NumberDetail >();
175
			_numbers.add( number );
176
		}
177
178
		public ArrayList< NumberDetail > getNumbers()
179
		{
180
			return _numbers;
181
		}
182
183
		public void addEmail( EmailDetail email )
184
		{
185
			if( email.getEmail() == null ) return;
186
			if( _emails == null )
187
				_emails = new ArrayList< EmailDetail >();
188
			_emails.add( email );
189
		}
190
191
		public ArrayList< EmailDetail > getEmails()
192
		{
193
			return _emails;
194
		}
195
196
		public void addAddress( AddressDetail address )
197
		{
198
			if( address.getAddress() == null ) return;
199
			if( _addresses == null )
200
				_addresses = new ArrayList< AddressDetail >();
201
			_addresses.add( address );
202
		}
203
204
		public ArrayList< AddressDetail > getAddresses()
205
		{
206
			return _addresses;
207
		}
208
209
		public String getPrimaryIdentifier()
210
		{
211
			if( _name != null )
212
				return _name;
213
214
			if( _organisations != null &&
215
				_organisations.get( 0 ).getOrganisation() != null )
216
				return _organisations.get( 0 ).getOrganisation();
217
218
			if( _numbers!= null &&
219
				_numbers.get( 0 ).getNumber() != null )
220
				return _numbers.get( 0 ).getNumber();
221
222
			if( _emails!= null &&
223
				_emails.get( 0 ).getEmail() != null )
224
				return _emails.get( 0 ).getEmail();
225
226
			// no primary identifier
227
			return null;
228
		}
229
	}
230
231
	@SuppressWarnings( "serial" )
232
	protected class AbortExportException extends Exception { };
233
234
	public Exporter( Doit doit )
235
	{
236
		_doit = doit;
237
	}
238
239
	@Override
240
	public void run()
241
	{
242
		try
243
		{
244
			// update UI
245
			setProgressMessage( R.string.doit_scanning );
246
247
			// do the export
248
			exportContacts();
249
250
			// done!
251
			finish( ACTION_ALLDONE );
252
		}
253
		catch( AbortExportException e )
254
		{}
255
256
		// flag as finished to prevent interrupts
257
		setIsFinished();
258
	}
259
260
	synchronized private void setIsFinished()
261
	{
262
		_is_finished = true;
263
	}
264
265
	protected void exportContacts() throws AbortExportException
266
	{
267
		// set up a contact reader
268
		ContactReader contact_reader = new ContactsContactReader( _doit, this );
269
		int num_contacts = contact_reader.getNumContacts();
270
		if( num_contacts == 0 )
271
			showError( R.string.error_nothingtodo );
272
273
		// count the number of contacts and set the progress bar max
274
		setProgress( 0 );
275
		setProgressMax( num_contacts );
276
277
		checkAbort();
278
		preExport();
279
280
		// loop through contacts
281
		int count = 0;
282
		while( true ) {
283
			checkAbort();
284
			ContactData contact = new ContactData();
285
			if( !contact_reader.getNextContact( contact ) )
286
				break;
287
288
			// export this one
289
			checkAbort();
290
			if( exportContact( contact ) )
291
				_doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTWRITTEN );
292
			else
293
				_doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTSKIPPED );
294
			setProgress( count++ );
295
		}
296
		setProgress( num_contacts );
297
298
		postExport();
299
	}
300
301
	public void wake()
302
	{
303
		wake( 0 );
304
	}
305
306
	synchronized public void wake( int response )
307
	{
308
		_response = response;
309
		notify();
310
	}
311
312
	synchronized public boolean setAbort()
313
	{
314
		if( !_is_finished && !_abort ) {
315
			_abort = true;
316
			notify();
317
			return true;
318
		}
319
		return false;
320
	}
321
322
	protected SharedPreferences getSharedPreferences()
323
	{
324
		return _doit.getSharedPreferences();
325
	}
326
327
	protected void showError( int res ) throws AbortExportException
328
	{
329
		showError( _doit.getText( res ).toString() );
330
	}
331
332
	synchronized protected void showError( String message )
333
			throws AbortExportException
334
	{
335
		checkAbort();
336
		_doit._handler.sendMessage( Message.obtain(
337
			_doit._handler, Doit.MESSAGE_ERROR, message ) );
338
		try {
339
			wait();
340
		}
341
		catch( InterruptedException e ) { }
342
343
		// no need to check if an abortion happened during the wait, we are
344
		// about to finish anyway!
345
		finish( ACTION_ABORT );
346
	}
347
348
	protected void showFatalError( int res ) throws AbortExportException
349
	{
350
		showFatalError( _doit.getText( res ).toString() );
351
	}
352
353
	synchronized protected void showFatalError( String message )
354
			throws AbortExportException
355
	{
356
		checkAbort();
357
		_doit._handler.sendMessage( Message.obtain(
358
			_doit._handler, Doit.MESSAGE_ERROR, message ) );
359
		try {
360
			wait();
361
		}
362
		catch( InterruptedException e ) { }
363
364
		// no need to check if an abortion happened during the wait, we are
365
		// about to finish anyway!
366
		finish( ACTION_ABORT );
367
	}
368
369
	protected boolean showContinue( int res ) throws AbortExportException
370
	{
371
		return showContinue( _doit.getText( res ).toString() );
372
	}
373
374
	synchronized protected boolean showContinue( String message )
375
			throws AbortExportException
376
	{
377
		checkAbort();
378
		_doit._handler.sendMessage( Message.obtain(
379
			_doit._handler, Doit.MESSAGE_CONTINUEORABORT, message ) );
380
		try {
381
			wait();
382
		}
383
		catch( InterruptedException e ) { }
384
385
		// check if an abortion happened during the wait
386
		checkAbort();
387
388
		return _response == RESPONSE_POSITIVE;
389
	}
390
391
	protected void setProgressMessage( int res ) throws AbortExportException
392
	{
393
		checkAbort();
394
		_doit._handler.sendMessage( Message.obtain( _doit._handler,
395
			Doit.MESSAGE_SETPROGRESSMESSAGE, getText( res ) ) );
396
	}
397
398
	protected void setProgressMax( int max_progress )
399
			throws AbortExportException
400
	{
401
		checkAbort();
402
		_doit._handler.sendMessage( Message.obtain(
403
			_doit._handler, Doit.MESSAGE_SETMAXPROGRESS,
404
			new Integer( max_progress ) ) );
405
	}
406
407
	protected void setTmpProgress( int tmp_progress )
408
		throws AbortExportException
409
	{
410
		checkAbort();
411
		_doit._handler.sendMessage( Message.obtain(
412
			_doit._handler, Doit.MESSAGE_SETTMPPROGRESS,
413
			new Integer( tmp_progress ) ) );
414
	}
415
416
	protected void setProgress( int progress ) throws AbortExportException
417
	{
418
		checkAbort();
419
		_doit._handler.sendMessage( Message.obtain(
420
			_doit._handler, Doit.MESSAGE_SETPROGRESS,
421
			new Integer( progress ) ) );
422
	}
423
424
	protected void finish( int action ) throws AbortExportException
425
	{
426
		// update UI to reflect action
427
		int message;
428
		switch( action )
429
		{
430
		case ACTION_ALLDONE:	message = Doit.MESSAGE_ALLDONE; break;
431
		default:	// fall through
432
		case ACTION_ABORT:		message = Doit.MESSAGE_ABORT; break;
433
		}
434
		_doit._handler.sendEmptyMessage( message );
435
436
		// stop
437
		throw new AbortExportException();
438
	}
439
440
	protected CharSequence getText( int res )
441
	{
442
		return _doit.getText( res );
443
	}
444
445
	protected void skipContact() throws AbortExportException
446
	{
447
		checkAbort();
448
		_doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTSKIPPED );
449
	}
450
451
	synchronized protected void checkAbort() throws AbortExportException
452
	{
453
		if( _abort ) {
454
			// stop
455
			throw new AbortExportException();
456
		}
457
	}
458
459
	protected void preExport() throws AbortExportException
460
	{
461
	}
462
463
	protected boolean exportContact( ContactData contact )
464
		throws AbortExportException
465
	{
466
		throw new UnsupportedOperationException();
467
	}
468
469
	protected void postExport() throws AbortExportException
470
	{
471
	}
472
473
}