/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
 *
12 by edam
changed all the URLs to ed.am, including copyrights, package names and project
4
 * Copyright (C) 2011 Tim Marston <tim@ed.am>
5 by edam
- added ContactReader interface
5
 *
6
 * This file is part of the Export Contacts program (hereafter referred
7
 * to as "this program"). For more information, see
12 by edam
changed all the URLs to ed.am, including copyrights, package names and project
8
 * http://ed.am/dev/android/export-contacts
5 by edam
- added ContactReader interface
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
12 by edam
changed all the URLs to ed.am, including copyrights, package names and project
24
package am.ed.exportcontacts;
5 by edam
- added ContactReader interface
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
11 by edam
continued renaming contact readers to accessors
268
		ContactAccessor contact_reader =
269
			new ContactsContactAccessor( _doit, this );
5 by edam
- added ContactReader interface
270
		int num_contacts = contact_reader.getNumContacts();
271
		if( num_contacts == 0 )
272
			showError( R.string.error_nothingtodo );
273
274
		// count the number of contacts and set the progress bar max
275
		setProgress( 0 );
276
		setProgressMax( num_contacts );
277
278
		checkAbort();
279
		preExport();
280
281
		// loop through contacts
282
		int count = 0;
283
		while( true ) {
284
			checkAbort();
285
			ContactData contact = new ContactData();
286
			if( !contact_reader.getNextContact( contact ) )
287
				break;
288
289
			// export this one
290
			checkAbort();
291
			if( exportContact( contact ) )
292
				_doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTWRITTEN );
293
			else
294
				_doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTSKIPPED );
295
			setProgress( count++ );
296
		}
297
		setProgress( num_contacts );
298
299
		postExport();
300
	}
301
302
	public void wake()
303
	{
304
		wake( 0 );
305
	}
306
307
	synchronized public void wake( int response )
308
	{
309
		_response = response;
310
		notify();
311
	}
312
313
	synchronized public boolean setAbort()
314
	{
315
		if( !_is_finished && !_abort ) {
316
			_abort = true;
317
			notify();
318
			return true;
319
		}
320
		return false;
321
	}
322
323
	protected SharedPreferences getSharedPreferences()
324
	{
325
		return _doit.getSharedPreferences();
326
	}
327
328
	protected void showError( int res ) throws AbortExportException
329
	{
330
		showError( _doit.getText( res ).toString() );
331
	}
332
333
	synchronized protected void showError( String message )
334
			throws AbortExportException
335
	{
336
		checkAbort();
337
		_doit._handler.sendMessage( Message.obtain(
338
			_doit._handler, Doit.MESSAGE_ERROR, message ) );
339
		try {
340
			wait();
341
		}
342
		catch( InterruptedException e ) { }
343
344
		// no need to check if an abortion happened during the wait, we are
345
		// about to finish anyway!
346
		finish( ACTION_ABORT );
347
	}
348
349
	protected void showFatalError( int res ) throws AbortExportException
350
	{
351
		showFatalError( _doit.getText( res ).toString() );
352
	}
353
354
	synchronized protected void showFatalError( String message )
355
			throws AbortExportException
356
	{
357
		checkAbort();
358
		_doit._handler.sendMessage( Message.obtain(
359
			_doit._handler, Doit.MESSAGE_ERROR, message ) );
360
		try {
361
			wait();
362
		}
363
		catch( InterruptedException e ) { }
364
365
		// no need to check if an abortion happened during the wait, we are
366
		// about to finish anyway!
367
		finish( ACTION_ABORT );
368
	}
369
370
	protected boolean showContinue( int res ) throws AbortExportException
371
	{
372
		return showContinue( _doit.getText( res ).toString() );
373
	}
374
375
	synchronized protected boolean showContinue( String message )
376
			throws AbortExportException
377
	{
378
		checkAbort();
379
		_doit._handler.sendMessage( Message.obtain(
380
			_doit._handler, Doit.MESSAGE_CONTINUEORABORT, message ) );
381
		try {
382
			wait();
383
		}
384
		catch( InterruptedException e ) { }
385
386
		// check if an abortion happened during the wait
387
		checkAbort();
388
389
		return _response == RESPONSE_POSITIVE;
390
	}
391
392
	protected void setProgressMessage( int res ) throws AbortExportException
393
	{
394
		checkAbort();
395
		_doit._handler.sendMessage( Message.obtain( _doit._handler,
396
			Doit.MESSAGE_SETPROGRESSMESSAGE, getText( res ) ) );
397
	}
398
399
	protected void setProgressMax( int max_progress )
400
			throws AbortExportException
401
	{
402
		checkAbort();
403
		_doit._handler.sendMessage( Message.obtain(
404
			_doit._handler, Doit.MESSAGE_SETMAXPROGRESS,
405
			new Integer( max_progress ) ) );
406
	}
407
408
	protected void setTmpProgress( int tmp_progress )
409
		throws AbortExportException
410
	{
411
		checkAbort();
412
		_doit._handler.sendMessage( Message.obtain(
413
			_doit._handler, Doit.MESSAGE_SETTMPPROGRESS,
414
			new Integer( tmp_progress ) ) );
415
	}
416
417
	protected void setProgress( int progress ) throws AbortExportException
418
	{
419
		checkAbort();
420
		_doit._handler.sendMessage( Message.obtain(
421
			_doit._handler, Doit.MESSAGE_SETPROGRESS,
422
			new Integer( progress ) ) );
423
	}
424
425
	protected void finish( int action ) throws AbortExportException
426
	{
427
		// update UI to reflect action
428
		int message;
429
		switch( action )
430
		{
431
		case ACTION_ALLDONE:	message = Doit.MESSAGE_ALLDONE; break;
432
		default:	// fall through
433
		case ACTION_ABORT:		message = Doit.MESSAGE_ABORT; break;
434
		}
435
		_doit._handler.sendEmptyMessage( message );
436
437
		// stop
438
		throw new AbortExportException();
439
	}
440
441
	protected CharSequence getText( int res )
442
	{
443
		return _doit.getText( res );
444
	}
445
446
	protected void skipContact() throws AbortExportException
447
	{
448
		checkAbort();
449
		_doit._handler.sendEmptyMessage( Doit.MESSAGE_CONTACTSKIPPED );
450
	}
451
452
	synchronized protected void checkAbort() throws AbortExportException
453
	{
454
		if( _abort ) {
455
			// stop
456
			throw new AbortExportException();
457
		}
458
	}
459
460
	protected void preExport() throws AbortExportException
461
	{
462
	}
463
464
	protected boolean exportContact( ContactData contact )
465
		throws AbortExportException
466
	{
467
		throw new UnsupportedOperationException();
468
	}
469
470
	protected void postExport() throws AbortExportException
471
	{
472
	}
473
474
}